You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@superset.apache.org by "1sanqian (via GitHub)" <gi...@apache.org> on 2025/12/27 00:19:20 UTC
[D] How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot? [superset]
GitHub user 1sanqian created a discussion: How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot?
How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot?I'm using C#, and I'm using Supersest version 4.0.1.
GitHub link: https://github.com/apache/superset/discussions/36845
----
This is an automatically sent email for notifications@superset.apache.org.
To unsubscribe, please send an email to: notifications-unsubscribe@superset.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [D] How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot? [superset]
Posted by "dosubot[bot] (via GitHub)" <gi...@apache.org>.
GitHub user dosubot[bot] edited a comment on the discussion: How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot?
<!-- Answer -->
To address 502 Bad Gateway errors in Superset caused by high server load, network issues, or timeouts, focus on these areas:
**1. Increase timeouts and enable retries:**
- In `superset_config.py`, raise `SUPERSET_WEBSERVER_TIMEOUT` (e.g., to 300 seconds), `SQLLAB_TIMEOUT`, and `SQLLAB_ASYNC_TIME_LIMIT_SEC` for long queries.
- For screenshot automation, set `SCREENSHOT_LOCATE_WAIT` and `SCREENSHOT_LOAD_WAIT` to higher values (e.g., 120–600 seconds) to give charts more time to render before timing out [[example config](https://github.com/apache/superset/issues/5993#issuecomment-3284091878)].
- Enable and tune Superset's HTTP retry logic for transient 502/503/504 errors:
```python
SUPERSET_CLIENT_RETRY_ATTEMPTS = 3
SUPERSET_CLIENT_RETRY_DELAY = 1000 # ms
SUPERSET_CLIENT_RETRY_BACKOFF_MULTIPLIER = 2
SUPERSET_CLIENT_RETRY_MAX_DELAY = 10000 # ms
SUPERSET_CLIENT_RETRY_JITTER_MAX = 1000 # ms
SUPERSET_CLIENT_RETRY_STATUS_CODES = [502, 503, 504]
```
This helps Superset automatically retry failed chart data requests with exponential backoff and jitter [[details](https://github.com/apache/superset/pull/34290)].
**2. Tune your proxy and web server:**
- In Nginx, increase `proxy_read_timeout`, `proxy_connect_timeout`, and `proxy_send_timeout` to be higher than your Superset/Gunicorn timeouts to avoid premature 502/504 errors [[discussion](https://github.com/apache/superset/discussions/31743#discussioncomment-11767901)].
- For Gunicorn, increase the keepalive setting to handle more concurrent users and avoid ECONNRESET errors that can manifest as 502s [[discussion](https://github.com/apache/superset/discussions/33373)].
**3. Scale and monitor resources:**
- Make sure your Superset server and database have enough CPU and RAM. 8GB RAM and 2vCPUs is a baseline for moderate use, but usage spikes (e.g., many users loading dashboards at once) may require more [[faq](https://github.com/apache/superset/blob/master/docs/docs/faq.mdx)].
- Monitor server, database, and network health. Look for slow queries, high CPU/memory usage, or network bottlenecks.
**4. Optimize queries and database performance:**
- Slow or complex queries are a common cause of timeouts and 502 errors. Optimize your dashboards and underlying SQL, and consider using a more performant database engine if needed [[faq](https://github.com/apache/superset/blob/master/docs/docs/faq.mdx)].
**5. Use asynchronous query execution:**
- Enable async queries in Superset (via Celery) to allow long-running queries to complete without blocking the web server, reducing the risk of timeouts and 502 errors [[async config](https://github.com/apache/superset/blob/master/docs/docs/configuration/async-queries-celery.mdx)].
**6. Troubleshoot persistent errors:**
- Check Superset, database, and proxy logs for errors or timeouts.
- Verify network connectivity between Superset, the database, and any proxies.
- If using Docker/Kubernetes, ensure the worker containers have access to the Superset instance and required headless browsers for screenshots.
These steps should help reduce the frequency of 502 errors and improve the reliability of chart rendering and screenshot automation in Superset.
<!-- Dosu Comment Footer -->
*To reply, just mention [@dosu](https://go.dosu.dev/dosubot?utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=reply-with-mention&utm_term=apache%2Fsuperset).*
---
Share context across your team and agents. Try [Dosu](https://dosu.dev?utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=knowledge-infrastructure-tagline&utm_term=apache%2Fsuperset).
[](https://app.dosu.dev/response-feedback?utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=knowledge-infrastructure-feedback&utm_term=apache%2Fsuperset&message_id=8984e039-efce-4833-bd09-1151609af240) [](https://github.dosu.com/apache/superset?utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=knowledge-infrastructure-learn-repo&utm_term=apache%2Fsuperset) [](https://app.dosu.dev/signup?referrer=openSource&source=github-footer&utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=knowledge-infrastructure-add-team&utm_term=apache%2Fsuperset)
GitHub link: https://github.com/apache/superset/discussions/36845#discussioncomment-15349764
----
This is an automatically sent email for notifications@superset.apache.org.
To unsubscribe, please send an email to: notifications-unsubscribe@superset.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [D] How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot? [superset]
Posted by "dosubot[bot] (via GitHub)" <gi...@apache.org>.
GitHub user dosubot[bot] edited a comment on the discussion: How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot?
<!-- Answer -->
A 502 Bad Gateway error during chart rendering in Superset usually means the backend or a proxy (like nginx) failed to process a chart data request—often due to server load, network issues, or timeouts. Superset and Playwright can only wait for the page and chart containers to load, but they can't fix server-side errors; if the API returns a 502, the chart will show an error and the screenshot will capture that state.
To reduce these errors and ensure all data is loaded before screenshots:
- Superset has built-in retry logic for transient 502/503/504 errors when fetching chart data. You can tune this in `superset_config.py` with settings like `SUPERSET_CLIENT_RETRY_ATTEMPTS`, `SUPERSET_CLIENT_RETRY_DELAY`, and related options. This helps automatically retry failed chart data requests before giving up, making dashboards more resilient to temporary backend issues [[details](https://github.com/apache/superset/pull/34290)].
- Increase timeouts for chart rendering and screenshot automation: set `SCREENSHOT_LOCATE_WAIT` and `SCREENSHOT_LOAD_WAIT` to higher values (e.g., 60–120 seconds) to give slow charts more time to load [[details](https://github.com/apache/superset/issues/5993#issuecomment-2828358239)].
- Make sure your Playwright script waits for all `.chart-container` elements to be visible and all `.loading` elements to disappear before taking a screenshot. This ensures the page is as "ready" as possible [[details](https://github.com/apache/superset/discussions/36839)].
- If you see persistent 502 errors, check Superset server logs, database health, and proxy/gateway timeout settings (e.g., `proxy_read_timeout` in nginx). High server load, slow queries, or restrictive proxy timeouts are common causes [[details](https://github.com/apache/superset/discussions/31743#discussioncomment-11767901)].
- For intermittent errors, the retry logic and increased timeouts usually help. For persistent errors, you may need to optimize your queries, increase server resources, or adjust proxy/database timeouts.
If you want to programmatically detect error states in Playwright, look for elements with `role="alert"` and extract error messages from `.antd5-modal-content .antd5-modal-body` before taking the screenshot. If you see a 502 error message, you can choose to retry, log, or fail the test as appropriate.
Let me know if you want example config snippets or more troubleshooting steps for your environment.
<!-- Dosu Comment Footer -->
*To reply, just mention [@dosu](https://go.dosu.dev/dosubot?utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=reply-with-mention&utm_term=apache%2Fsuperset).*
---
Docs are dead. Just use [Dosu](https://dosu.dev?utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=static-docs-tagline&utm_term=apache%2Fsuperset).
[](https://app.dosu.dev/response-feedback?utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=static-docs-feedback&utm_term=apache%2Fsuperset&message_id=ddb9a57b-f054-48b6-b4cf-9865e4f4e3b9) [](https://github.dosu.com/apache/superset?utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=static-docs-ask-repo&utm_term=apache%2Fsuperset) [](https://app.dosu.dev/signup?referrer=openSource&source=github-footer&utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=static-docs-share-team&utm_term=apache%2Fsuperset)
GitHub link: https://github.com/apache/superset/discussions/36845#discussioncomment-15349732
----
This is an automatically sent email for notifications@superset.apache.org.
To unsubscribe, please send an email to: notifications-unsubscribe@superset.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [D] How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot? [superset]
Posted by "1sanqian (via GitHub)" <gi...@apache.org>.
GitHub user 1sanqian added a comment to the discussion: How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot?
Before taking a screenshot of the chart, when checking the page rendering data, I kept getting the error message: "Chart data verification failed: A temporary server error was detected (please try again later): Unexpected error <html> <head><title>502 Bad Gateway</title></head> <body> <center><h1>502 Bad Gateway</h1></center> <hr><center>nginx</center> </body> </html> <!-- a padding to disable MSIE and Chrome friendly error page --> <!-- a padding to disable MSIE and Chrome friendly error page --> <!-- a padding to disable MSIE and Chrome friendly error page --> <!-- a padding to disable MSIE and Chrome friendly error page --> <!-- a padding to disable MSIE and Chrome friendly error page --> <!-- a padding to disable MSIE and Chrome friendly error page --> <!-- a padding to disable MSIE and Chrome friendly error page --> Is there any way to make sure all the page data is loaded?[@dosu](https://go.dosu.dev/dosubot).
GitHub link: https://github.com/apache/superset/discussions/36845#discussioncomment-15349724
----
This is an automatically sent email for notifications@superset.apache.org.
To unsubscribe, please send an email to: notifications-unsubscribe@superset.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [D] How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot? [superset]
Posted by "1sanqian (via GitHub)" <gi...@apache.org>.
GitHub user 1sanqian added a comment to the discussion: How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot?
I've already determined the page has rendered based on the message "Wait for all .loading elements to disappear (status is 'detached'), which means the chart has finished rendering." However, there's a brief period where the .loading elements disappear but the chart hasn't appeared yet. How can I fix this?[@dosu](https://go.dosu.dev/dosubot)
GitHub link: https://github.com/apache/superset/discussions/36845#discussioncomment-15359760
----
This is an automatically sent email for notifications@superset.apache.org.
To unsubscribe, please send an email to: notifications-unsubscribe@superset.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [D] How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot? [superset]
Posted by "1sanqian (via GitHub)" <gi...@apache.org>.
GitHub user 1sanqian added a comment to the discussion: How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot?
private async Task<(bool isValid, string reason)> PerformFinalChartValidationAsync(IPage page, string originalTemplateUrl)
{
var validationStartTime = DateTime.UtcNow;
var maxValidationTime = TimeSpan.FromMinutes(5);
var validationAttempt = 0;
Log.Information("Starting 5-minute final chart validation cycle...");
while (DateTime.UtcNow - validationStartTime < maxValidationTime)
{
validationAttempt++;
var elapsed = DateTime.UtcNow - validationStartTime;
Log.Information("Final validation attempt {Attempt} at {Elapsed:F1} minutes", validationAttempt, elapsed.TotalMinutes);
try
{
Log.Information("Step 1: Waiting for main dashboard container...");
await page.WaitForSelectorAsync(".dashboard, [class*='dashboard'], .main-content, [class*='main']",
new PageWaitForSelectorOptions { Timeout = 10000 }).ConfigureAwait(false);
Log.Information("Dashboard container found");
Log.Information("Step 2: Waiting for all chart containers...");
var chartContainers = await page.QuerySelectorAllAsync(".chart-container, [class*='chart-container'], [data-test*='chart'], .viz-chart");
Log.Information("Found {Count} chart containers", chartContainers.Count);
var visibleContainers = 0;
var failedContainers = new List<string>();
foreach (var container in chartContainers)
{
try
{
await container.WaitForElementStateAsync(ElementState.Visible, new ElementHandleWaitForElementStateOptions { Timeout = 30000 });
visibleContainers++;
}
catch (Exception ex)
{
var containerInfo = await container.EvaluateAsync<string>("element => element.outerHTML.substring(0, 200)").ConfigureAwait(false);
failedContainers.Add($"Container failed to become visible: {containerInfo}");
Log.Information(ex, "Chart container failed to become visible within timeout");
}
}
Log.Information("Chart containers visibility check: {Visible}/{Total} visible", visibleContainers, chartContainers.Count);
if (failedContainers.Count > 0)
{
Log.Warning("Some chart containers failed to become visible: {Failed}/{Total}",
failedContainers.Count, chartContainers.Count);
if (failedContainers.Count > chartContainers.Count * 0.5)
{
var pageDiagnostics = await GatherPageDiagnosticsAsync(page);
throw new Exception($"过多图表容器不可见 ({failedContainers.Count}/{chartContainers.Count}): {string.Join("; ", failedContainers)}. 页面诊断: {pageDiagnostics}");
}
}
Log.Information("All chart containers are visible");
Log.Information("Step 3: Waiting for all loading elements to disappear (SCREENSHOT_LOAD_WAIT style)...");
var loadingSelectors = new[]
{
".loading",
".spinner",
".loader",
"[class*='loading']",
"[class*='is-loading']",
"[class*='css-19o2u55']",
"[class*='spinner']",
"[class*='ant-spin']",
".anticon-loading"
};
var startTime = DateTime.UtcNow;
var maxWaitTime = TimeSpan.FromSeconds(60);
while (DateTime.UtcNow - startTime < maxWaitTime)
{
var hasLoadingElements = false;
foreach (var selector in loadingSelectors)
{
try
{
var loadingElements = await page.QuerySelectorAllAsync(selector);
foreach (var loadingElement in loadingElements)
{
var isAttached = await loadingElement.EvaluateAsync<bool>("element => document.contains(element)");
if (isAttached)
{
var isVisible = await loadingElement.IsVisibleAsync();
if (isVisible)
{
hasLoadingElements = true;
break;
}
}
}
if (hasLoadingElements) break;
}
catch
{
}
}
if (!hasLoadingElements)
{
Log.Information("All loading elements have disappeared (detached)");
break;
}
await page.WaitForTimeoutAsync(500);
}
Log.Information("Step 4: Waiting for each chart's content to be visible...");
var chartContentValidationErrors = new List<string>();
foreach (var chart in chartContainers)
{
try
{
var chartId = await chart.GetAttributeAsync("data-test-chart-id") ??
await chart.GetAttributeAsync("data-chart-id") ??
await chart.GetAttributeAsync("id");
if (!string.IsNullOrEmpty(chartId))
{
await page.WaitForSelectorAsync($"#chart-id-{chartId}", new PageWaitForSelectorOptions
{
State = WaitForSelectorState.Visible,
Timeout = 10000
});
Log.Information("Chart content visible for chart ID: {ChartId}", chartId);
}
else
{
await chart.WaitForSelectorAsync("svg, canvas, .chart-content, [class*='chart']", new ElementHandleWaitForSelectorOptions
{
State = WaitForSelectorState.Visible,
Timeout = 10000
});
Log.Information("Chart content visible for container (fallback method)");
}
}
catch (Exception ex)
{
var containerInfo = await chart.EvaluateAsync<string>("element => element.outerHTML.substring(0, 200)").ConfigureAwait(false);
chartContentValidationErrors.Add($"Chart content validation failed: {containerInfo}");
Log.Warning(ex, "Failed to validate chart content visibility for container");
}
}
if (chartContentValidationErrors.Count > 0)
{
Log.Warning("Some charts failed content validation: {Count}/{Total}",
chartContentValidationErrors.Count, chartContainers.Count);
if (chartContentValidationErrors.Count > chartContainers.Count * 0.3) // 30% threshold
{
throw new Exception($"过多图表内容未正确渲染 ({chartContentValidationErrors.Count}/{chartContainers.Count}): {string.Join("; ", chartContentValidationErrors)}");
}
}
Log.Information("Step 5: Waiting for animation delay and headstart (Superset SCREENSHOT_SELENIUM_ANIMATION_WAIT)...");
var animationWaitMs = 2000;
var headstartMs = 500;
var totalWaitMs = animationWaitMs + headstartMs;
await page.WaitForTimeoutAsync(totalWaitMs);
Log.Information("Animation and headstart delay completed ({AnimationMs}ms + {HeadstartMs}ms = {TotalMs}ms) - Superset timing parameters",
animationWaitMs, headstartMs, totalWaitMs);
var remainingLoadingElements = 0;
foreach (var selector in loadingSelectors)
{
try
{
var count = await page.Locator(selector).CountAsync();
remainingLoadingElements += count;
}
catch
{
}
}
if (remainingLoadingElements > 0)
{
Log.Information("Warning: {Count} loading elements still present after validation", remainingLoadingElements);
if (remainingLoadingElements <= 3)
{
Log.Information("Accepting validation with {Count} remaining loading elements (likely minor UI elements)", remainingLoadingElements);
}
else
{
Log.Information("Accepting validation with {Count} remaining loading elements (likely minor UI elements)", remainingLoadingElements);
return (false, $"TimeOut");
}
}
Log.Information("Step 6: Checking for error alerts and attempting recovery...");
var (errorMessages, recoveryAttempted) = await CheckAndHandleErrorAlertsWithRecoveryAsync(page, chartContainers);
if (errorMessages.Count > 0)
{
Log.Warning("Found {Count} error alerts on page", errorMessages.Count);
foreach (var errorMsg in errorMessages)
{
Log.Warning("Error alert: {Message}", errorMsg);
}
var criticalErrors = errorMessages.Where(msg =>
msg.Contains("502") || msg.Contains("500") ||
msg.Contains("Bad Gateway") ||
msg.Contains("Connection failed") || msg.Contains("Network error")).ToList();
if (criticalErrors.Count > 0)
{
var temporaryErrors = criticalErrors.Where(msg =>
msg.Contains("502") || msg.Contains("503") || msg.Contains("504") ||
msg.Contains("Bad Gateway") || msg.Contains("Service Unavailable") ||
msg.Contains("Gateway Timeout") ||
msg.Contains("Connection failed") || msg.Contains("Network error")).ToList();
var permanentErrors = criticalErrors.Except(temporaryErrors).ToList();
Log.Information("Detected temporary server errors, will refresh and retry...");
throw new Exception($"临时服务器错误: {string.Join("; ", temporaryErrors)}");
}
else
{
if (recoveryAttempted)
{
Log.Information("Recovery attempted for non-critical errors, waiting for charts to reload...");
await page.WaitForTimeoutAsync(3000);
var remainingErrors = await CheckForRemainingErrorsAsync(page);
if (remainingErrors.Count > 0)
{
Log.Information("Some errors persist after recovery attempt @{error}", string.Join("; ", remainingErrors));
return (false, $"TimeOut");
}
else
{
Log.Information("Chart recovery successful, proceeding with screenshot");
}
}
else
{
Log.Information("Non-critical errors found but no recovery attempted, proceeding with screenshot");
}
}
}
var totalChartContainers = chartContainers.Count;
Log.Information("Final validation: {TotalCharts} chart containers validated", totalChartContainers);
if (totalChartContainers == 0)
{
throw new Exception("未找到任何图表容器");
}
Log.Information("Step 7: Final stability check...");
var isStable = await page.EvaluateAsync<bool>(@"
() => {
// 检查页面是否还在滚动或有动画
return !window.scrolling && document.readyState === 'complete';
}
").ConfigureAwait(false);
if (!isStable)
{
Log.Information("Page not fully stable, waiting additional time...");
await page.WaitForTimeoutAsync(1000);
}
Log.Information("Superset-style validation completed successfully");
Log.Information("Final validation passed, executing page preparation steps for screenshot...");
await ScrollToBottomWithPlaywrightAsync(page).ConfigureAwait(false);
await WaitForPageStableWithPlaywrightAsync(page, maxWaitSeconds: 3).ConfigureAwait(false);
try
{
var collapseButton = page.Locator("button[data-test='filter-bar__collapse-button']");
await collapseButton.WaitForAsync(new LocatorWaitForOptions
{
State = WaitForSelectorState.Visible,
Timeout = 10000
}).ConfigureAwait(false);
await collapseButton.WaitForAsync(new LocatorWaitForOptions
{
State = WaitForSelectorState.Attached,
Timeout = 10000
}).ConfigureAwait(false);
await collapseButton.ClickAsync(new LocatorClickOptions
{
Timeout = 10000
}).ConfigureAwait(false);
await page.WaitForTimeoutAsync(500);
Log.Information("Successfully clicked collapse button after final validation");
}
catch (Exception ex)
{
Log.Information(ex, "Failed to click collapse button after final validation");
}
await ClearHoverStateWithPlaywrightAsync(page).ConfigureAwait(false);
Log.Information("Page preparation completed after final validation");
return (true, "Superset样式验证通过");
}
catch (Exception ex)
{
Log.Information("Validation attempt {Attempt} failed: {Error}", validationAttempt, ex.Message);
if (DateTime.UtcNow - validationStartTime < maxValidationTime)
{
Log.Information("Refreshing page and retrying validation (attempt {Attempt})...", validationAttempt + 1);
try
{
await page.ReloadAsync(new PageReloadOptions { WaitUntil = WaitUntilState.DOMContentLoaded });
await page.WaitForTimeoutAsync(2000);
continue;
}
catch (Exception reloadEx)
{
Log.Information(reloadEx, "Failed to reload page for retry");
continue;
}
}
else
{
var totalElapsed = DateTime.UtcNow - validationStartTime;
Log.Information("Final chart validation timeout after {Elapsed:F1} minutes and {Attempts} attempts",
totalElapsed.TotalMinutes, validationAttempt);
return (false, "TimeOut");
}
}
}
var finalElapsed = DateTime.UtcNow - validationStartTime;
Log.Error("Final chart validation timeout after {Elapsed:F1} minutes", finalElapsed.TotalMinutes);
return (false, "TimeOut");
}Could you please take a look at this code and see if it can effectively solve the problems of server load and complete screenshots/charts?
GitHub link: https://github.com/apache/superset/discussions/36845#discussioncomment-15359900
----
This is an automatically sent email for notifications@superset.apache.org.
To unsubscribe, please send an email to: notifications-unsubscribe@superset.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [D] How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot? [superset]
Posted by "dosubot[bot] (via GitHub)" <gi...@apache.org>.
GitHub user dosubot[bot] added a comment to the discussion: How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot?
<!-- Answer -->
Your validation method closely matches Superset’s own Playwright/Selenium screenshot automation and covers all the critical steps: waiting for the dashboard and chart containers, waiting for loading elements to disappear, checking for chart content, waiting for animation delays, detecting error alerts (including 502/503/504), and retrying on temporary failures. This is the recommended approach for ensuring charts are fully rendered before screenshots and for handling transient server load issues in Superset ([reference](https://github.com/apache/superset/blob/master/superset/utils/webdriver.py)).
However, no frontend automation can fully “solve” backend server load or persistent 502 errors—your code can only detect, retry, and fail gracefully if the backend cannot deliver data. For best results, make sure your Superset backend is tuned: increase timeouts like `SCREENSHOT_LOCATE_WAIT` and `SCREENSHOT_LOAD_WAIT`, enable HTTP retries (`SUPERSET_CLIENT_RETRY_ATTEMPTS` etc.), and optimize your database and proxy settings ([reference](https://github.com/apache/superset/blob/master/superset/config.py)). For very large dashboards, consider increasing your max wait times and resource limits.
If you want to go even further, you could check for the presence of login screens (to catch authentication/session issues), and monitor resource usage on your Superset server during heavy loads. But overall, your method is robust and aligns with Superset’s best practices for screenshot and chart completeness validation.
<!-- Dosu Comment Footer -->
*To reply, just mention [@dosu](https://go.dosu.dev/dosubot).*
---
<sup>How did I do? [Good](https://app.dosu.dev/response-feedback/99a0c0f0-d528-41bb-bca6-ef499f905a67?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/99a0c0f0-d528-41bb-bca6-ef499f905a67?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/99a0c0f0-d528-41bb-bca6-ef499f905a67?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/99a0c0f0-d528-41bb-bca6-ef499f905a67?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/99a0c0f0-d528-41bb-bca6-ef499f905a67?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/99a0c0f0-d528-41bb-bca6-ef499f905a67?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/99a0c0f0-d528-41bb-bca6-ef499f905a67?feedback_type=other)</sup>
[](https://app.dosu.dev/a28d3c7e-a9d3-459e-9fb6-3a6f9ff4f357/ask?utm_source=github) [](https://cursor.com/link/prompt?text=Your%20validation%20method%20closely%20matches%20Superset%E2%80%99s%20own%20Playwright/Selenium%20screenshot%20automation%20and%20covers%20all%20the%20critical%20steps%3A%20waiting%20for%20the%20dashboard%20and%20chart%20containers%2C%20waiting%20for%20loading%20elements%20to%20disappear%2C%20checking%20for%20chart%20content%2C%20waiting%20for%20animation%20delays%2C%20detecting%20error%20alerts%20%28including%20502/503/504%29%2C%20and%20retrying%20on%20temporary%20failures.%20This%20is%20the%20recommended%20approach%20for%20ensuring%20charts%20are%20fully%20rendered%20before%20screenshots%20and%20for%20handling%20transient%20server%20load%20issues%20in%20Superset%C2%A0%28%5Breference%5D%28https%3A//github.com/apache/superset/blob/master/superset/util
s/webdriver.py%29%29.%0A%0AHowever%2C%20no%20frontend%20automation%20can%20fully%20%E2%80%9Csolve%E2%80%9D%20backend%20server%20load%20or%20persistent%20502%20errors%E2%80%94your%20code%20can%20only%20detect%2C%20retry%2C%20and%20fail%20gracefully%20if%20the%20backend%20cannot%20deliver%20data.%20For%20best%20results%2C%20make%20sure%20your%20Superset%20backend%20is%20tuned%3A%20increase%20timeouts%20like%20%60SCREENSHOT_LOCATE_WAIT%60%20and%20%60SCREENSHOT_LOAD_WAIT%60%2C%20enable%20HTTP%20retries%20%28%60SUPERSET_CLIENT_RETRY_ATTEMPTS%60%20etc.%29%2C%20and%20optimize%20your%20database%20and%20proxy%20settings%C2%A0%28%5Breference%5D%28https%3A//github.com/apache/superset/blob/master/superset/config.py%29%29.%20For%20very%20large%20dashboards%2C%20consider%20increasing%20your%20max%20wait%20times%20and%20resource%20limits.%0A%0AIf%20you%20want%20to%20go%20even%20further%2C%20you%20could%20check%20for%20the%20presence%20of%20login%20screens%20%28to%20catch%20authentication/session%2
0issues%29%2C%20and%20monitor%20resource%20usage%20on%20your%20Superset%20server%20during%20heavy%20loads.%20But%20overall%2C%20your%20method%20is%20robust%20and%20aligns%20with%20Superset%E2%80%99s%20best%20practices%20for%20screenshot%20and%20chart%20completeness%20validation.) [](https://go.dosu.dev/discord-bot) [](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/apache/superset/discussions/36845)
GitHub link: https://github.com/apache/superset/discussions/36845#discussioncomment-15359906
----
This is an automatically sent email for notifications@superset.apache.org.
To unsubscribe, please send an email to: notifications-unsubscribe@superset.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [D] How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot? [superset]
Posted by "dosubot[bot] (via GitHub)" <gi...@apache.org>.
GitHub user dosubot[bot] edited a comment on the discussion: How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot?
<!-- Answer -->
Your validation method closely matches Superset’s own Playwright/Selenium screenshot automation and covers all the critical steps: waiting for the dashboard and chart containers, waiting for loading elements to disappear, checking for chart content, waiting for animation delays, detecting error alerts (including 502/503/504), and retrying on temporary failures. This is the recommended approach for ensuring charts are fully rendered before screenshots and for handling transient server load issues in Superset ([reference](https://github.com/apache/superset/blob/master/superset/utils/webdriver.py)).
However, no frontend automation can fully “solve” backend server load or persistent 502 errors—your code can only detect, retry, and fail gracefully if the backend cannot deliver data. For best results, make sure your Superset backend is tuned: increase timeouts like `SCREENSHOT_LOCATE_WAIT` and `SCREENSHOT_LOAD_WAIT`, enable HTTP retries (`SUPERSET_CLIENT_RETRY_ATTEMPTS` etc.), and optimize your database and proxy settings ([reference](https://github.com/apache/superset/blob/master/superset/config.py)). For very large dashboards, consider increasing your max wait times and resource limits.
If you want to go even further, you could check for the presence of login screens (to catch authentication/session issues), and monitor resource usage on your Superset server during heavy loads. But overall, your method is robust and aligns with Superset’s best practices for screenshot and chart completeness validation.
<!-- Dosu Comment Footer -->
*To reply, just mention [@dosu](https://go.dosu.dev/dosubot?utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=reply-with-mention&utm_term=apache%2Fsuperset).*
---
Docs are dead. Just use [Dosu](https://dosu.dev?utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=static-docs-tagline&utm_term=apache%2Fsuperset).
[](https://app.dosu.dev/response-feedback?utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=static-docs-feedback&utm_term=apache%2Fsuperset&message_id=99a0c0f0-d528-41bb-bca6-ef499f905a67) [](https://github.dosu.com/apache/superset?utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=static-docs-ask-repo&utm_term=apache%2Fsuperset) [](https://app.dosu.dev/signup?referrer=openSource&source=github-footer&utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=static-docs-share-team&utm_term=apache%2Fsuperset)
GitHub link: https://github.com/apache/superset/discussions/36845#discussioncomment-15359906
----
This is an automatically sent email for notifications@superset.apache.org.
To unsubscribe, please send an email to: notifications-unsubscribe@superset.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [D] How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot? [superset]
Posted by "dosubot[bot] (via GitHub)" <gi...@apache.org>.
GitHub user dosubot[bot] edited a comment on the discussion: How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot?
<!-- Answer -->
To ensure all Superset charts and data are fully rendered and error-free before taking a screenshot with Playwright in C#, follow the same logic used by Superset's built-in Playwright automation:
1. Navigate to your Superset dashboard or chart URL.
2. Wait for the main container (e.g., `.dashboard` or the relevant class) to appear.
3. Wait for all `.chart-container` elements to be visible.
4. Wait for all `.loading` elements to disappear (state "detached"), which means charts have finished rendering.
5. (Optional) Wait a few seconds for chart animations to complete.
6. Check for error elements with `role="alert"` and extract error messages from `.antd5-modal-content .antd5-modal-body` if present.
7. Take the screenshot.
Here’s a C# Playwright code snippet that implements this logic:
```csharp
using Microsoft.Playwright;
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions { Headless = true });
var page = await browser.NewPageAsync();
await page.GotoAsync("https://your-superset-url/superset/dashboard/123/", new PageGotoOptions { WaitUntil = WaitUntilState.Load });
// Wait for main dashboard container
await page.WaitForSelectorAsync(".dashboard");
// Wait for all chart containers to be visible
var chartContainers = await page.QuerySelectorAllAsync(".chart-container");
foreach (var chart in chartContainers)
{
await chart.WaitForElementStateAsync(ElementState.Visible);
}
// Wait for all loading spinners to disappear
var loadingElements = await page.QuerySelectorAllAsync(".loading");
foreach (var loading in loadingElements)
{
await loading.WaitForElementStateAsync(ElementState.Detached);
}
// Optional: wait for chart animations to finish
await page.WaitForTimeoutAsync(5000);
// Check for unexpected errors
var alerts = await page.QuerySelectorAllAsync("[role='alert']");
foreach (var alert in alerts)
{
var seeMoreBtn = await alert.QuerySelectorAsync("[role='button']");
if (seeMoreBtn != null)
{
await seeMoreBtn.ClickAsync();
var modalBody = await page.QuerySelectorAsync(".antd5-modal-content .antd5-modal-body");
if (modalBody != null)
{
var errorMsg = await modalBody.InnerTextAsync();
// Handle or log errorMsg as needed
}
var closeBtn = await page.QuerySelectorAsync(".antd5-modal-content .antd5-modal-close");
if (closeBtn != null)
await closeBtn.ClickAsync();
await page.WaitForSelectorAsync(".antd5-modal-content", new PageWaitForSelectorOptions { State = WaitForSelectorState.Detached });
}
}
// Take the screenshot
await page.ScreenshotAsync(new PageScreenshotOptions { Path = "dashboard.png" });
```
For large dashboards, consider a tiled screenshot approach: scroll the dashboard in view-sized increments, wait for content to settle after each scroll, and stitch the images together. This is how Superset handles dashboards that extend beyond the viewport [[source]](https://github.com/apache/superset/pull/34561).
You can tune timeouts and delays using Superset config options like `SCREENSHOT_PLAYWRIGHT_DEFAULT_TIMEOUT`, `SCREENSHOT_SELENIUM_ANIMATION_WAIT`, and `SCREENSHOT_SELENIUM_HEADSTART` [[source]](https://github.com/apache/superset/blob/master/superset/config.py).
There are no C#-specific examples in the Superset codebase, but the DOM structure and selectors are the same as in Python, so this approach is portable [[source]](https://github.com/apache/superset/discussions/36839).
<!-- Dosu Comment Footer -->
*To reply, just mention [@dosu](https://go.dosu.dev/dosubot?utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=reply-with-mention&utm_term=apache%2Fsuperset).*
---
Share context across your team and agents. Try [Dosu](https://dosu.dev?utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=knowledge-infrastructure-tagline&utm_term=apache%2Fsuperset).
[](https://app.dosu.dev/response-feedback?utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=knowledge-infrastructure-feedback&utm_term=apache%2Fsuperset&message_id=eec8805a-0752-4c3a-b1d8-e8ef30ae6c9a) [](https://github.dosu.com/apache/superset?utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=knowledge-infrastructure-learn-repo&utm_term=apache%2Fsuperset) [](https://app.dosu.dev/signup?referrer=openSource&source=github-footer&utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=knowledge-infrastructure-add-team&utm_term=apache%2Fsuperset)
GitHub link: https://github.com/apache/superset/discussions/36845#discussioncomment-15349414
----
This is an automatically sent email for notifications@superset.apache.org.
To unsubscribe, please send an email to: notifications-unsubscribe@superset.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [D] How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot? [superset]
Posted by "dosubot[bot] (via GitHub)" <gi...@apache.org>.
GitHub user dosubot[bot] edited a comment on the discussion: How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot?
<!-- Answer -->
This happens because Superset removes the `.loading` spinner as soon as the data fetch finishes, but the chart's actual rendering (drawing SVG, canvas, or DOM updates) can take a bit longer due to asynchronous UI updates and animations. So, waiting only for `.loading` to disappear isn't always enough.
To make your Playwright automation more robust, you should:
- Wait for all `.chart-container` elements to be visible.
- Wait for all `.loading` elements to be detached.
- Then, for each chart, wait for a specific chart content element (like `#chart-id-{chartId}`) to be visible—this element only appears when the chart is fully rendered.
- Optionally, add a short extra wait (e.g., 1–2 seconds) for chart animations to finish. Superset's own screenshot logic uses a configurable animation wait for this reason.
Example C# Playwright logic:
```csharp
// Wait for all chart containers to be visible
var chartContainers = await page.QuerySelectorAllAsync(".chart-container");
foreach (var chart in chartContainers)
{
await chart.WaitForElementStateAsync(ElementState.Visible);
}
// Wait for all loading spinners to disappear
var loadingElements = await page.QuerySelectorAllAsync(".loading");
foreach (var loading in loadingElements)
{
await loading.WaitForElementStateAsync(ElementState.Detached);
}
// Wait for each chart's content to be visible (replace with actual chart IDs)
foreach (var chart in chartContainers)
{
var chartId = await chart.GetAttributeAsync("data-test-chart-id");
if (!string.IsNullOrEmpty(chartId))
{
await page.WaitForSelectorAsync($"#chart-id-{chartId}", new PageWaitForSelectorOptions { State = WaitForSelectorState.Visible });
}
}
// Optional: wait for chart animations to finish
await page.WaitForTimeoutAsync(1000); // 1 second
```
This approach matches how Superset's own automation and Cypress tests ensure charts are fully rendered before screenshots or assertions. You can tune the extra wait with the `SCREENSHOT_SELENIUM_ANIMATION_WAIT` config if needed. More details:
[Superset Playwright/Selenium screenshot logic](https://github.com/apache/superset/blob/master/superset/utils/webdriver.py)
[Why waiting for .loading isn't enough](https://github.com/apache/superset/blob/master/superset-frontend/cypress-base/cypress/utils/index.ts)
[ChartRenderer rendering lifecycle](https://github.com/apache/superset/blob/master/superset-frontend/src/components/Chart/ChartRenderer.jsx)
<!-- Dosu Comment Footer -->
*To reply, just mention [@dosu](https://go.dosu.dev/dosubot?utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=reply-with-mention&utm_term=apache%2Fsuperset).*
---
Share context across your team and agents. Try [Dosu](https://dosu.dev?utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=knowledge-infrastructure-tagline&utm_term=apache%2Fsuperset).
[](https://app.dosu.dev/response-feedback?utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=knowledge-infrastructure-feedback&utm_term=apache%2Fsuperset&message_id=3fb2c37a-5a6e-49c4-be9f-60e908da0ba2) [](https://github.dosu.com/apache/superset?utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=knowledge-infrastructure-learn-repo&utm_term=apache%2Fsuperset) [](https://app.dosu.dev/signup?referrer=openSource&source=github-footer&utm_source=github&utm_medium=bot-comment&utm_campaign=github-comment-footer-20260415&utm_content=knowledge-infrastructure-add-team&utm_term=apache%2Fsuperset)
GitHub link: https://github.com/apache/superset/discussions/36845#discussioncomment-15359770
----
This is an automatically sent email for notifications@superset.apache.org.
To unsubscribe, please send an email to: notifications-unsubscribe@superset.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [D] How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot? [superset]
Posted by "1sanqian (via GitHub)" <gi...@apache.org>.
GitHub user 1sanqian edited a comment on the discussion: How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot?
Could you please take a look at this code and see if it can effectively solve the problems of server load and complete screenshots/charts?[@dosu](https://go.dosu.dev/dosubot).
private async Task<(bool isValid, string reason)> PerformFinalChartValidationAsync(IPage page, string originalTemplateUrl)
{
var validationStartTime = DateTime.UtcNow;
var maxValidationTime = TimeSpan.FromMinutes(5);
var validationAttempt = 0;
Log.Information("Starting 5-minute final chart validation cycle...");
while (DateTime.UtcNow - validationStartTime < maxValidationTime)
{
validationAttempt++;
var elapsed = DateTime.UtcNow - validationStartTime;
Log.Information("Final validation attempt {Attempt} at {Elapsed:F1} minutes", validationAttempt, elapsed.TotalMinutes);
try
{
Log.Information("Step 1: Waiting for main dashboard container...");
await page.WaitForSelectorAsync(".dashboard, [class*='dashboard'], .main-content, [class*='main']",
new PageWaitForSelectorOptions { Timeout = 10000 }).ConfigureAwait(false);
Log.Information("Dashboard container found");
Log.Information("Step 2: Waiting for all chart containers...");
var chartContainers = await page.QuerySelectorAllAsync(".chart-container, [class*='chart-container'], [data-test*='chart'], .viz-chart");
Log.Information("Found {Count} chart containers", chartContainers.Count);
var visibleContainers = 0;
var failedContainers = new List<string>();
foreach (var container in chartContainers)
{
try
{
await container.WaitForElementStateAsync(ElementState.Visible, new ElementHandleWaitForElementStateOptions { Timeout = 30000 });
visibleContainers++;
}
catch (Exception ex)
{
var containerInfo = await container.EvaluateAsync<string>("element => element.outerHTML.substring(0, 200)").ConfigureAwait(false);
failedContainers.Add($"Container failed to become visible: {containerInfo}");
Log.Information(ex, "Chart container failed to become visible within timeout");
}
}
Log.Information("Chart containers visibility check: {Visible}/{Total} visible", visibleContainers, chartContainers.Count);
if (failedContainers.Count > 0)
{
Log.Warning("Some chart containers failed to become visible: {Failed}/{Total}",
failedContainers.Count, chartContainers.Count);
if (failedContainers.Count > chartContainers.Count * 0.5)
{
var pageDiagnostics = await GatherPageDiagnosticsAsync(page);
throw new Exception($"过多图表容器不可见 ({failedContainers.Count}/{chartContainers.Count}): {string.Join("; ", failedContainers)}. 页面诊断: {pageDiagnostics}");
}
}
Log.Information("All chart containers are visible");
Log.Information("Step 3: Waiting for all loading elements to disappear (SCREENSHOT_LOAD_WAIT style)...");
var loadingSelectors = new[]
{
".loading",
".spinner",
".loader",
"[class*='loading']",
"[class*='is-loading']",
"[class*='css-19o2u55']",
"[class*='spinner']",
"[class*='ant-spin']",
".anticon-loading"
};
var startTime = DateTime.UtcNow;
var maxWaitTime = TimeSpan.FromSeconds(60);
while (DateTime.UtcNow - startTime < maxWaitTime)
{
var hasLoadingElements = false;
foreach (var selector in loadingSelectors)
{
try
{
var loadingElements = await page.QuerySelectorAllAsync(selector);
foreach (var loadingElement in loadingElements)
{
var isAttached = await loadingElement.EvaluateAsync<bool>("element => document.contains(element)");
if (isAttached)
{
var isVisible = await loadingElement.IsVisibleAsync();
if (isVisible)
{
hasLoadingElements = true;
break;
}
}
}
if (hasLoadingElements) break;
}
catch
{
}
}
if (!hasLoadingElements)
{
Log.Information("All loading elements have disappeared (detached)");
break;
}
await page.WaitForTimeoutAsync(500);
}
Log.Information("Step 4: Waiting for each chart's content to be visible...");
var chartContentValidationErrors = new List<string>();
foreach (var chart in chartContainers)
{
try
{
var chartId = await chart.GetAttributeAsync("data-test-chart-id") ??
await chart.GetAttributeAsync("data-chart-id") ??
await chart.GetAttributeAsync("id");
if (!string.IsNullOrEmpty(chartId))
{
await page.WaitForSelectorAsync($"#chart-id-{chartId}", new PageWaitForSelectorOptions
{
State = WaitForSelectorState.Visible,
Timeout = 10000
});
Log.Information("Chart content visible for chart ID: {ChartId}", chartId);
}
else
{
await chart.WaitForSelectorAsync("svg, canvas, .chart-content, [class*='chart']", new ElementHandleWaitForSelectorOptions
{
State = WaitForSelectorState.Visible,
Timeout = 10000
});
Log.Information("Chart content visible for container (fallback method)");
}
}
catch (Exception ex)
{
var containerInfo = await chart.EvaluateAsync<string>("element => element.outerHTML.substring(0, 200)").ConfigureAwait(false);
chartContentValidationErrors.Add($"Chart content validation failed: {containerInfo}");
Log.Warning(ex, "Failed to validate chart content visibility for container");
}
}
if (chartContentValidationErrors.Count > 0)
{
Log.Warning("Some charts failed content validation: {Count}/{Total}",
chartContentValidationErrors.Count, chartContainers.Count);
if (chartContentValidationErrors.Count > chartContainers.Count * 0.3) // 30% threshold
{
throw new Exception($"过多图表内容未正确渲染 ({chartContentValidationErrors.Count}/{chartContainers.Count}): {string.Join("; ", chartContentValidationErrors)}");
}
}
Log.Information("Step 5: Waiting for animation delay and headstart (Superset SCREENSHOT_SELENIUM_ANIMATION_WAIT)...");
var animationWaitMs = 2000;
var headstartMs = 500;
var totalWaitMs = animationWaitMs + headstartMs;
await page.WaitForTimeoutAsync(totalWaitMs);
Log.Information("Animation and headstart delay completed ({AnimationMs}ms + {HeadstartMs}ms = {TotalMs}ms) - Superset timing parameters",
animationWaitMs, headstartMs, totalWaitMs);
var remainingLoadingElements = 0;
foreach (var selector in loadingSelectors)
{
try
{
var count = await page.Locator(selector).CountAsync();
remainingLoadingElements += count;
}
catch
{
}
}
if (remainingLoadingElements > 0)
{
Log.Information("Warning: {Count} loading elements still present after validation", remainingLoadingElements);
if (remainingLoadingElements <= 3)
{
Log.Information("Accepting validation with {Count} remaining loading elements (likely minor UI elements)", remainingLoadingElements);
}
else
{
Log.Information("Accepting validation with {Count} remaining loading elements (likely minor UI elements)", remainingLoadingElements);
return (false, $"TimeOut");
}
}
Log.Information("Step 6: Checking for error alerts and attempting recovery...");
var (errorMessages, recoveryAttempted) = await CheckAndHandleErrorAlertsWithRecoveryAsync(page, chartContainers);
if (errorMessages.Count > 0)
{
Log.Warning("Found {Count} error alerts on page", errorMessages.Count);
foreach (var errorMsg in errorMessages)
{
Log.Warning("Error alert: {Message}", errorMsg);
}
var criticalErrors = errorMessages.Where(msg =>
msg.Contains("502") || msg.Contains("500") ||
msg.Contains("Bad Gateway") ||
msg.Contains("Connection failed") || msg.Contains("Network error")).ToList();
if (criticalErrors.Count > 0)
{
var temporaryErrors = criticalErrors.Where(msg =>
msg.Contains("502") || msg.Contains("503") || msg.Contains("504") ||
msg.Contains("Bad Gateway") || msg.Contains("Service Unavailable") ||
msg.Contains("Gateway Timeout") ||
msg.Contains("Connection failed") || msg.Contains("Network error")).ToList();
var permanentErrors = criticalErrors.Except(temporaryErrors).ToList();
Log.Information("Detected temporary server errors, will refresh and retry...");
throw new Exception($"临时服务器错误: {string.Join("; ", temporaryErrors)}");
}
else
{
if (recoveryAttempted)
{
Log.Information("Recovery attempted for non-critical errors, waiting for charts to reload...");
await page.WaitForTimeoutAsync(3000);
var remainingErrors = await CheckForRemainingErrorsAsync(page);
if (remainingErrors.Count > 0)
{
Log.Information("Some errors persist after recovery attempt @{error}", string.Join("; ", remainingErrors));
return (false, $"TimeOut");
}
else
{
Log.Information("Chart recovery successful, proceeding with screenshot");
}
}
else
{
Log.Information("Non-critical errors found but no recovery attempted, proceeding with screenshot");
}
}
}
var totalChartContainers = chartContainers.Count;
Log.Information("Final validation: {TotalCharts} chart containers validated", totalChartContainers);
if (totalChartContainers == 0)
{
throw new Exception("未找到任何图表容器");
}
Log.Information("Step 7: Final stability check...");
var isStable = await page.EvaluateAsync<bool>(@"
() => {
// 检查页面是否还在滚动或有动画
return !window.scrolling && document.readyState === 'complete';
}
").ConfigureAwait(false);
if (!isStable)
{
Log.Information("Page not fully stable, waiting additional time...");
await page.WaitForTimeoutAsync(1000);
}
Log.Information("Superset-style validation completed successfully");
Log.Information("Final validation passed, executing page preparation steps for screenshot...");
await ScrollToBottomWithPlaywrightAsync(page).ConfigureAwait(false);
await WaitForPageStableWithPlaywrightAsync(page, maxWaitSeconds: 3).ConfigureAwait(false);
try
{
var collapseButton = page.Locator("button[data-test='filter-bar__collapse-button']");
await collapseButton.WaitForAsync(new LocatorWaitForOptions
{
State = WaitForSelectorState.Visible,
Timeout = 10000
}).ConfigureAwait(false);
await collapseButton.WaitForAsync(new LocatorWaitForOptions
{
State = WaitForSelectorState.Attached,
Timeout = 10000
}).ConfigureAwait(false);
await collapseButton.ClickAsync(new LocatorClickOptions
{
Timeout = 10000
}).ConfigureAwait(false);
await page.WaitForTimeoutAsync(500);
Log.Information("Successfully clicked collapse button after final validation");
}
catch (Exception ex)
{
Log.Information(ex, "Failed to click collapse button after final validation");
}
await ClearHoverStateWithPlaywrightAsync(page).ConfigureAwait(false);
Log.Information("Page preparation completed after final validation");
return (true, "Superset样式验证通过");
}
catch (Exception ex)
{
Log.Information("Validation attempt {Attempt} failed: {Error}", validationAttempt, ex.Message);
if (DateTime.UtcNow - validationStartTime < maxValidationTime)
{
Log.Information("Refreshing page and retrying validation (attempt {Attempt})...", validationAttempt + 1);
try
{
await page.ReloadAsync(new PageReloadOptions { WaitUntil = WaitUntilState.DOMContentLoaded });
await page.WaitForTimeoutAsync(2000);
continue;
}
catch (Exception reloadEx)
{
Log.Information(reloadEx, "Failed to reload page for retry");
continue;
}
}
else
{
var totalElapsed = DateTime.UtcNow - validationStartTime;
Log.Information("Final chart validation timeout after {Elapsed:F1} minutes and {Attempts} attempts",
totalElapsed.TotalMinutes, validationAttempt);
return (false, "TimeOut");
}
}
}
var finalElapsed = DateTime.UtcNow - validationStartTime;
Log.Error("Final chart validation timeout after {Elapsed:F1} minutes", finalElapsed.TotalMinutes);
return (false, "TimeOut");
}
GitHub link: https://github.com/apache/superset/discussions/36845#discussioncomment-15359900
----
This is an automatically sent email for notifications@superset.apache.org.
To unsubscribe, please send an email to: notifications-unsubscribe@superset.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [D] How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot? [superset]
Posted by "dosubot[bot] (via GitHub)" <gi...@apache.org>.
GitHub user dosubot[bot] added a comment to the discussion: How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot?
<!-- Answer -->
A 502 Bad Gateway error during chart rendering in Superset usually means the backend or a proxy (like nginx) failed to process a chart data request—often due to server load, network issues, or timeouts. Superset and Playwright can only wait for the page and chart containers to load, but they can't fix server-side errors; if the API returns a 502, the chart will show an error and the screenshot will capture that state.
To reduce these errors and ensure all data is loaded before screenshots:
- Superset has built-in retry logic for transient 502/503/504 errors when fetching chart data. You can tune this in `superset_config.py` with settings like `SUPERSET_CLIENT_RETRY_ATTEMPTS`, `SUPERSET_CLIENT_RETRY_DELAY`, and related options. This helps automatically retry failed chart data requests before giving up, making dashboards more resilient to temporary backend issues [[details](https://github.com/apache/superset/pull/34290)].
- Increase timeouts for chart rendering and screenshot automation: set `SCREENSHOT_LOCATE_WAIT` and `SCREENSHOT_LOAD_WAIT` to higher values (e.g., 60–120 seconds) to give slow charts more time to load [[details](https://github.com/apache/superset/issues/5993#issuecomment-2828358239)].
- Make sure your Playwright script waits for all `.chart-container` elements to be visible and all `.loading` elements to disappear before taking a screenshot. This ensures the page is as "ready" as possible [[details](https://github.com/apache/superset/discussions/36839)].
- If you see persistent 502 errors, check Superset server logs, database health, and proxy/gateway timeout settings (e.g., `proxy_read_timeout` in nginx). High server load, slow queries, or restrictive proxy timeouts are common causes [[details](https://github.com/apache/superset/discussions/31743#discussioncomment-11767901)].
- For intermittent errors, the retry logic and increased timeouts usually help. For persistent errors, you may need to optimize your queries, increase server resources, or adjust proxy/database timeouts.
If you want to programmatically detect error states in Playwright, look for elements with `role="alert"` and extract error messages from `.antd5-modal-content .antd5-modal-body` before taking the screenshot. If you see a 502 error message, you can choose to retry, log, or fail the test as appropriate.
Let me know if you want example config snippets or more troubleshooting steps for your environment.
<!-- Dosu Comment Footer -->
*To reply, just mention [@dosu](https://go.dosu.dev/dosubot).*
---
<sup>How did I do? [Good](https://app.dosu.dev/response-feedback/ddb9a57b-f054-48b6-b4cf-9865e4f4e3b9?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/ddb9a57b-f054-48b6-b4cf-9865e4f4e3b9?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/ddb9a57b-f054-48b6-b4cf-9865e4f4e3b9?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/ddb9a57b-f054-48b6-b4cf-9865e4f4e3b9?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/ddb9a57b-f054-48b6-b4cf-9865e4f4e3b9?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/ddb9a57b-f054-48b6-b4cf-9865e4f4e3b9?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/ddb9a57b-f054-48b6-b4cf-9865e4f4e3b9?feedback_type=other)</sup>
[](https://app.dosu.dev/a28d3c7e-a9d3-459e-9fb6-3a6f9ff4f357/ask?utm_source=github) [](https://cursor.com/link/prompt?text=A%20502%20Bad%20Gateway%20error%20during%20chart%20rendering%20in%20Superset%20usually%20means%20the%20backend%20or%20a%20proxy%20%28like%20nginx%29%20failed%20to%20process%20a%20chart%20data%20request%E2%80%94often%20due%20to%20server%20load%2C%20network%20issues%2C%20or%20timeouts.%20Superset%20and%20Playwright%20can%20only%20wait%20for%20the%20page%20and%20chart%20containers%20to%20load%2C%20but%20they%20can%27t%20fix%20server-side%20errors%3B%20if%20the%20API%20returns%20a%20502%2C%20the%20chart%20will%20show%20an%20error%20and%20the%20screenshot%20will%20capture%20that%20state.%0A%0ATo%20reduce%20these%20errors%20and%20ensure%20all%20data%20is%20loaded%20before%20screenshots%3A%0A%0A-%20Superset%20has%20built-in%20retry%20logic%20for%20transient%
20502/503/504%20errors%20when%20fetching%20chart%20data.%20You%20can%20tune%20this%20in%20%60superset_config.py%60%20with%20settings%20like%20%60SUPERSET_CLIENT_RETRY_ATTEMPTS%60%2C%20%60SUPERSET_CLIENT_RETRY_DELAY%60%2C%20and%20related%20options.%20This%20helps%20automatically%20retry%20failed%20chart%20data%20requests%20before%20giving%20up%2C%20making%20dashboards%20more%20resilient%20to%20temporary%20backend%20issues%20%5B%5Bdetails%5D%28https%3A//github.com/apache/superset/pull/34290%29%5D.%0A-%20Increase%20timeouts%20for%20chart%20rendering%20and%20screenshot%20automation%3A%20set%20%60SCREENSHOT_LOCATE_WAIT%60%20and%20%60SCREENSHOT_LOAD_WAIT%60%20to%20higher%20values%20%28e.g.%2C%2060%E2%80%93120%20seconds%29%20to%20give%20slow%20charts%20more%20time%20to%20load%20%5B%5Bdetails%5D%28https%3A//github.com/apache/superset/issues/5993%23issuecomment-2828358239%29%5D.%0A-%20Make%20sure%20your%20Playwright%20script%20waits%20for%20all%20%60.chart-container%60%20elements%20to%20be%2
0visible%20and%20all%20%60.loading%60%20elements%20to%20disappear%20before%20taking%20a%20screenshot.%20This%20ensures%20the%20page%20is%20as%20%22ready%22%20as%20possible%20%5B%5Bdetails%5D%28https%3A//github.com/apache/superset/discussions/36839%29%5D.%0A-%20If%20you%20see%20persistent%20502%20errors%2C%20check%20Superset%20server%20logs%2C%20database%20health%2C%20and%20proxy/gateway%20timeout%20settings%20%28e.g.%2C%20%60proxy_read_timeout%60%20in%20nginx%29.%20High%20server%20load%2C%20slow%20queries%2C%20or%20restrictive%20proxy%20timeouts%20are%20common%20causes%20%5B%5Bdetails%5D%28https%3A//github.com/apache/superset/discussions/31743%23discussioncomment-11767901%29%5D.%0A-%20For%20intermittent%20errors%2C%20the%20retry%20logic%20and%20increased%20timeouts%20usually%20help.%20For%20persistent%20errors%2C%20you%20may%20need%20to%20optimize%20your%20queries%2C%20increase%20server%20resources%2C%20or%20adjust%20proxy/database%20timeouts.%0A%0AIf%20you%20want%20to%20programmati
cally%20detect%20error%20states%20in%20Playwright%2C%20look%20for%20elements%20with%20%60role%3D%22alert%22%60%20and%20extract%20error%20messages%20from%20%60.antd5-modal-content%20.antd5-modal-body%60%20before%20taking%20the%20screenshot.%20If%20you%20see%20a%20502%20error%20message%2C%20you%20can%20choose%20to%20retry%2C%20log%2C%20or%20fail%20the%20test%20as%20appropriate.%0A%0ALet%20me%20know%20if%20you%20want%20example%20config%20snippets%20or%20more%20troubleshooting%20steps%20for%20your%20environment.) [](https://go.dosu.dev/discord-bot) [](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/apache/superset/discussions/36845)
GitHub link: https://github.com/apache/superset/discussions/36845#discussioncomment-15349732
----
This is an automatically sent email for notifications@superset.apache.org.
To unsubscribe, please send an email to: notifications-unsubscribe@superset.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [D] How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot? [superset]
Posted by "dosubot[bot] (via GitHub)" <gi...@apache.org>.
GitHub user dosubot[bot] added a comment to the discussion: How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot?
<!-- Answer -->
This happens because Superset removes the `.loading` spinner as soon as the data fetch finishes, but the chart's actual rendering (drawing SVG, canvas, or DOM updates) can take a bit longer due to asynchronous UI updates and animations. So, waiting only for `.loading` to disappear isn't always enough.
To make your Playwright automation more robust, you should:
- Wait for all `.chart-container` elements to be visible.
- Wait for all `.loading` elements to be detached.
- Then, for each chart, wait for a specific chart content element (like `#chart-id-{chartId}`) to be visible—this element only appears when the chart is fully rendered.
- Optionally, add a short extra wait (e.g., 1–2 seconds) for chart animations to finish. Superset's own screenshot logic uses a configurable animation wait for this reason.
Example C# Playwright logic:
```csharp
// Wait for all chart containers to be visible
var chartContainers = await page.QuerySelectorAllAsync(".chart-container");
foreach (var chart in chartContainers)
{
await chart.WaitForElementStateAsync(ElementState.Visible);
}
// Wait for all loading spinners to disappear
var loadingElements = await page.QuerySelectorAllAsync(".loading");
foreach (var loading in loadingElements)
{
await loading.WaitForElementStateAsync(ElementState.Detached);
}
// Wait for each chart's content to be visible (replace with actual chart IDs)
foreach (var chart in chartContainers)
{
var chartId = await chart.GetAttributeAsync("data-test-chart-id");
if (!string.IsNullOrEmpty(chartId))
{
await page.WaitForSelectorAsync($"#chart-id-{chartId}", new PageWaitForSelectorOptions { State = WaitForSelectorState.Visible });
}
}
// Optional: wait for chart animations to finish
await page.WaitForTimeoutAsync(1000); // 1 second
```
This approach matches how Superset's own automation and Cypress tests ensure charts are fully rendered before screenshots or assertions. You can tune the extra wait with the `SCREENSHOT_SELENIUM_ANIMATION_WAIT` config if needed. More details:
[Superset Playwright/Selenium screenshot logic](https://github.com/apache/superset/blob/master/superset/utils/webdriver.py)
[Why waiting for .loading isn't enough](https://github.com/apache/superset/blob/master/superset-frontend/cypress-base/cypress/utils/index.ts)
[ChartRenderer rendering lifecycle](https://github.com/apache/superset/blob/master/superset-frontend/src/components/Chart/ChartRenderer.jsx)
<!-- Dosu Comment Footer -->
*To reply, just mention [@dosu](https://go.dosu.dev/dosubot).*
---
<sup>How did I do? [Good](https://app.dosu.dev/response-feedback/3fb2c37a-5a6e-49c4-be9f-60e908da0ba2?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/3fb2c37a-5a6e-49c4-be9f-60e908da0ba2?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/3fb2c37a-5a6e-49c4-be9f-60e908da0ba2?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/3fb2c37a-5a6e-49c4-be9f-60e908da0ba2?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/3fb2c37a-5a6e-49c4-be9f-60e908da0ba2?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/3fb2c37a-5a6e-49c4-be9f-60e908da0ba2?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/3fb2c37a-5a6e-49c4-be9f-60e908da0ba2?feedback_type=other)</sup>
[](https://app.dosu.dev/a28d3c7e-a9d3-459e-9fb6-3a6f9ff4f357/ask?utm_source=github) [](https://cursor.com/link/prompt?text=This%20happens%20because%20Superset%20removes%20the%20%60.loading%60%20spinner%20as%20soon%20as%20the%20data%20fetch%20finishes%2C%20but%20the%20chart%27s%20actual%20rendering%20%28drawing%20SVG%2C%20canvas%2C%20or%20DOM%20updates%29%20can%20take%20a%20bit%20longer%20due%20to%20asynchronous%20UI%20updates%20and%20animations.%20So%2C%20waiting%20only%20for%20%60.loading%60%20to%20disappear%20isn%27t%20always%20enough.%0A%0ATo%20make%20your%20Playwright%20automation%20more%20robust%2C%20you%20should%3A%0A%0A-%20Wait%20for%20all%20%60.chart-container%60%20elements%20to%20be%20visible.%0A-%20Wait%20for%20all%20%60.loading%60%20elements%20to%20be%20detached.%0A-%20Then%2C%20for%20each%20chart%2C%20wait%20for%20a%20specific%20chart%20content%20element%20%28
like%20%60%23chart-id-%7BchartId%7D%60%29%20to%20be%20visible%E2%80%94this%20element%20only%20appears%20when%20the%20chart%20is%20fully%20rendered.%0A-%20Optionally%2C%20add%20a%20short%20extra%20wait%20%28e.g.%2C%201%E2%80%932%20seconds%29%20for%20chart%20animations%20to%20finish.%20Superset%27s%20own%20screenshot%20logic%20uses%20a%20configurable%20animation%20wait%20for%20this%20reason.%0A%0AExample%20C%23%20Playwright%20logic%3A%0A%0A%60%60%60csharp%0A//%20Wait%20for%20all%20chart%20containers%20to%20be%20visible%0Avar%20chartContainers%20%3D%20await%20page.QuerySelectorAllAsync%28%22.chart-container%22%29%3B%0Aforeach%20%28var%20chart%20in%20chartContainers%29%0A%7B%0A%20%20%20%20await%20chart.WaitForElementStateAsync%28ElementState.Visible%29%3B%0A%7D%0A%0A//%20Wait%20for%20all%20loading%20spinners%20to%20disappear%0Avar%20loadingElements%20%3D%20await%20page.QuerySelectorAllAsync%28%22.loading%22%29%3B%0Aforeach%20%28var%20loading%20in%20loadingElements%29%0A%7B%0A%20%20%20%2
0await%20loading.WaitForElementStateAsync%28ElementState.Detached%29%3B%0A%7D%0A%0A//%20Wait%20for%20each%20chart%27s%20content%20to%20be%20visible%20%28replace%20with%20actual%20chart%20IDs%29%0Aforeach%20%28var%20chart%20in%20chartContainers%29%0A%7B%0A%20%20%20%20var%20chartId%20%3D%20await%20chart.GetAttributeAsync%28%22data-test-chart-id%22%29%3B%0A%20%20%20%20if%20%28%21string.IsNullOrEmpty%28chartId%29%29%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20await%20page.WaitForSelectorAsync%28%24%22%23chart-id-%7BchartId%7D%22%2C%20new%20PageWaitForSelectorOptions%20%7B%20State%20%3D%20WaitForSelectorState.Visible%20%7D%29%3B%0A%20%20%20%20%7D%0A%7D%0A%0A//%20Optional%3A%20wait%20for%20chart%20animations%20to%20finish%0Aawait%20page.WaitForTimeoutAsync%281000%29%3B%20//%201%20second%0A%60%60%60%0A%0AThis%20approach%20matches%20how%20Superset%27s%20own%20automation%20and%20Cypress%20tests%20ensure%20charts%20are%20fully%20rendered%20before%20screenshots%20or%20assertions.%20You%20can%2
0tune%20the%20extra%20wait%20with%20the%20%60SCREENSHOT_SELENIUM_ANIMATION_WAIT%60%20config%20if%20needed.%20More%20details%3A%20%20%0A%5BSuperset%20Playwright/Selenium%20screenshot%20logic%5D%28https%3A//github.com/apache/superset/blob/master/superset/utils/webdriver.py%29%20%20%0A%5BWhy%20waiting%20for%20.loading%20isn%27t%20enough%5D%28https%3A//github.com/apache/superset/blob/master/superset-frontend/cypress-base/cypress/utils/index.ts%29%20%20%0A%5BChartRenderer%20rendering%20lifecycle%5D%28https%3A//github.com/apache/superset/blob/master/superset-frontend/src/components/Chart/ChartRenderer.jsx%29) [](https://go.dosu.dev/discord-bot) [](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/apache/superset/discussions/36845)
GitHub link: https://github.com/apache/superset/discussions/36845#discussioncomment-15359770
----
This is an automatically sent email for notifications@superset.apache.org.
To unsubscribe, please send an email to: notifications-unsubscribe@superset.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [D] How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot? [superset]
Posted by "dosubot[bot] (via GitHub)" <gi...@apache.org>.
GitHub user dosubot[bot] added a comment to the discussion: How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot?
<!-- Answer -->
To address 502 Bad Gateway errors in Superset caused by high server load, network issues, or timeouts, focus on these areas:
**1. Increase timeouts and enable retries:**
- In `superset_config.py`, raise `SUPERSET_WEBSERVER_TIMEOUT` (e.g., to 300 seconds), `SQLLAB_TIMEOUT`, and `SQLLAB_ASYNC_TIME_LIMIT_SEC` for long queries.
- For screenshot automation, set `SCREENSHOT_LOCATE_WAIT` and `SCREENSHOT_LOAD_WAIT` to higher values (e.g., 120–600 seconds) to give charts more time to render before timing out [[example config](https://github.com/apache/superset/issues/5993#issuecomment-3284091878)].
- Enable and tune Superset's HTTP retry logic for transient 502/503/504 errors:
```python
SUPERSET_CLIENT_RETRY_ATTEMPTS = 3
SUPERSET_CLIENT_RETRY_DELAY = 1000 # ms
SUPERSET_CLIENT_RETRY_BACKOFF_MULTIPLIER = 2
SUPERSET_CLIENT_RETRY_MAX_DELAY = 10000 # ms
SUPERSET_CLIENT_RETRY_JITTER_MAX = 1000 # ms
SUPERSET_CLIENT_RETRY_STATUS_CODES = [502, 503, 504]
```
This helps Superset automatically retry failed chart data requests with exponential backoff and jitter [[details](https://github.com/apache/superset/pull/34290)].
**2. Tune your proxy and web server:**
- In Nginx, increase `proxy_read_timeout`, `proxy_connect_timeout`, and `proxy_send_timeout` to be higher than your Superset/Gunicorn timeouts to avoid premature 502/504 errors [[discussion](https://github.com/apache/superset/discussions/31743#discussioncomment-11767901)].
- For Gunicorn, increase the keepalive setting to handle more concurrent users and avoid ECONNRESET errors that can manifest as 502s [[discussion](https://github.com/apache/superset/discussions/33373)].
**3. Scale and monitor resources:**
- Make sure your Superset server and database have enough CPU and RAM. 8GB RAM and 2vCPUs is a baseline for moderate use, but usage spikes (e.g., many users loading dashboards at once) may require more [[faq](https://github.com/apache/superset/blob/master/docs/docs/faq.mdx)].
- Monitor server, database, and network health. Look for slow queries, high CPU/memory usage, or network bottlenecks.
**4. Optimize queries and database performance:**
- Slow or complex queries are a common cause of timeouts and 502 errors. Optimize your dashboards and underlying SQL, and consider using a more performant database engine if needed [[faq](https://github.com/apache/superset/blob/master/docs/docs/faq.mdx)].
**5. Use asynchronous query execution:**
- Enable async queries in Superset (via Celery) to allow long-running queries to complete without blocking the web server, reducing the risk of timeouts and 502 errors [[async config](https://github.com/apache/superset/blob/master/docs/docs/configuration/async-queries-celery.mdx)].
**6. Troubleshoot persistent errors:**
- Check Superset, database, and proxy logs for errors or timeouts.
- Verify network connectivity between Superset, the database, and any proxies.
- If using Docker/Kubernetes, ensure the worker containers have access to the Superset instance and required headless browsers for screenshots.
These steps should help reduce the frequency of 502 errors and improve the reliability of chart rendering and screenshot automation in Superset.
<!-- Dosu Comment Footer -->
*To reply, just mention [@dosu](https://go.dosu.dev/dosubot).*
---
<sup>How did I do? [Good](https://app.dosu.dev/response-feedback/8984e039-efce-4833-bd09-1151609af240?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/8984e039-efce-4833-bd09-1151609af240?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/8984e039-efce-4833-bd09-1151609af240?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/8984e039-efce-4833-bd09-1151609af240?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/8984e039-efce-4833-bd09-1151609af240?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/8984e039-efce-4833-bd09-1151609af240?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/8984e039-efce-4833-bd09-1151609af240?feedback_type=other)</sup>
[](https://app.dosu.dev/a28d3c7e-a9d3-459e-9fb6-3a6f9ff4f357/ask?utm_source=github) [](https://cursor.com/link/prompt?text=To%20address%20502%20Bad%20Gateway%20errors%20in%20Superset%20caused%20by%20high%20server%20load%2C%20network%20issues%2C%20or%20timeouts%2C%20focus%20on%20these%20areas%3A%0A%0A%2A%2A1.%20Increase%20timeouts%20and%20enable%20retries%3A%2A%2A%20%20%0A-%20In%20%60superset_config.py%60%2C%20raise%20%60SUPERSET_WEBSERVER_TIMEOUT%60%20%28e.g.%2C%20to%20300%20seconds%29%2C%20%60SQLLAB_TIMEOUT%60%2C%20and%20%60SQLLAB_ASYNC_TIME_LIMIT_SEC%60%20for%20long%20queries.%20%20%0A-%20For%20screenshot%20automation%2C%20set%20%60SCREENSHOT_LOCATE_WAIT%60%20and%20%60SCREENSHOT_LOAD_WAIT%60%20to%20higher%20values%20%28e.g.%2C%20120%E2%80%93600%20seconds%29%20to%20give%20charts%20more%20time%20to%20render%20before%20timing%20out%20%5B%5Bexample%20config%5D%28https%3A//g
ithub.com/apache/superset/issues/5993%23issuecomment-3284091878%29%5D.%0A-%20Enable%20and%20tune%20Superset%27s%20HTTP%20retry%20logic%20for%20transient%20502/503/504%20errors%3A%0A%20%20%60%60%60python%0A%20%20SUPERSET_CLIENT_RETRY_ATTEMPTS%20%3D%203%0A%20%20SUPERSET_CLIENT_RETRY_DELAY%20%3D%201000%20%20%23%20ms%0A%20%20SUPERSET_CLIENT_RETRY_BACKOFF_MULTIPLIER%20%3D%202%0A%20%20SUPERSET_CLIENT_RETRY_MAX_DELAY%20%3D%2010000%20%20%23%20ms%0A%20%20SUPERSET_CLIENT_RETRY_JITTER_MAX%20%3D%201000%20%20%23%20ms%0A%20%20SUPERSET_CLIENT_RETRY_STATUS_CODES%20%3D%20%5B502%2C%20503%2C%20504%5D%0A%20%20%60%60%60%0A%20%20This%20helps%20Superset%20automatically%20retry%20failed%20chart%20data%20requests%20with%20exponential%20backoff%20and%20jitter%20%5B%5Bdetails%5D%28https%3A//github.com/apache/superset/pull/34290%29%5D.%0A%0A%2A%2A2.%20Tune%20your%20proxy%20and%20web%20server%3A%2A%2A%20%20%0A-%20In%20Nginx%2C%20increase%20%60proxy_read_timeout%60%2C%20%60proxy_connect_timeout%60%2C%20and%20%60
proxy_send_timeout%60%20to%20be%20higher%20than%20your%20Superset/Gunicorn%20timeouts%20to%20avoid%20premature%20502/504%20errors%20%5B%5Bdiscussion%5D%28https%3A//github.com/apache/superset/discussions/31743%23discussioncomment-11767901%29%5D.%0A-%20For%20Gunicorn%2C%20increase%20the%20keepalive%20setting%20to%20handle%20more%20concurrent%20users%20and%20avoid%20ECONNRESET%20errors%20that%20can%20manifest%20as%20502s%20%5B%5Bdiscussion%5D%28https%3A//github.com/apache/superset/discussions/33373%29%5D.%0A%0A%2A%2A3.%20Scale%20and%20monitor%20resources%3A%2A%2A%20%20%0A-%20Make%20sure%20your%20Superset%20server%20and%20database%20have%20enough%20CPU%20and%20RAM.%208GB%20RAM%20and%202vCPUs%20is%20a%20baseline%20for%20moderate%20use%2C%20but%20usage%20spikes%20%28e.g.%2C%20many%20users%20loading%20dashboards%20at%20once%29%20may%20require%20more%20%5B%5Bfaq%5D%28https%3A//github.com/apache/superset/blob/master/docs/docs/faq.mdx%29%5D.%0A-%20Monitor%20server%2C%20database%2C%20and%20net
work%20health.%20Look%20for%20slow%20queries%2C%20high%20CPU/memory%20usage%2C%20or%20network%20bottlenecks.%0A%0A%2A%2A4.%20Optimize%20queries%20and%20database%20performance%3A%2A%2A%20%20%0A-%20Slow%20or%20complex%20queries%20are%20a%20common%20cause%20of%20timeouts%20and%20502%20errors.%20Optimize%20your%20dashboards%20and%20underlying%20SQL%2C%20and%20consider%20using%20a%20more%20performant%20database%20engine%20if%20needed%20%5B%5Bfaq%5D%28https%3A//github.com/apache/superset/blob/master/docs/docs/faq.mdx%29%5D.%0A%0A%2A%2A5.%20Use%20asynchronous%20query%20execution%3A%2A%2A%20%20%0A-%20Enable%20async%20queries%20in%20Superset%20%28via%20Celery%29%20to%20allow%20long-running%20queries%20to%20complete%20without%20blocking%20the%20web%20server%2C%20reducing%20the%20risk%20of%20timeouts%20and%20502%20errors%20%5B%5Basync%20config%5D%28https%3A//github.com/apache/superset/blob/master/docs/docs/configuration/async-queries-celery.mdx%29%5D.%0A%0A%2A%2A6.%20Troubleshoot%20persistent%
20errors%3A%2A%2A%20%20%0A-%20Check%20Superset%2C%20database%2C%20and%20proxy%20logs%20for%20errors%20or%20timeouts.%0A-%20Verify%20network%20connectivity%20between%20Superset%2C%20the%20database%2C%20and%20any%20proxies.%0A-%20If%20using%20Docker/Kubernetes%2C%20ensure%20the%20worker%20containers%20have%20access%20to%20the%20Superset%20instance%20and%20required%20headless%20browsers%20for%20screenshots.%0A%0AThese%20steps%20should%20help%20reduce%20the%20frequency%20of%20502%20errors%20and%20improve%20the%20reliability%20of%20chart%20rendering%20and%20screenshot%20automation%20in%20Superset.) [](https://go.dosu.dev/discord-bot) [](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/apache/superset/discussions/36845)
GitHub link: https://github.com/apache/superset/discussions/36845#discussioncomment-15349764
----
This is an automatically sent email for notifications@superset.apache.org.
To unsubscribe, please send an email to: notifications-unsubscribe@superset.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [D] How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot? [superset]
Posted by "1sanqian (via GitHub)" <gi...@apache.org>.
GitHub user 1sanqian added a comment to the discussion: How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot?
A 502 Bad Gateway error when rendering a chart in Superset typically means that the backend or proxy (such as nginx) failed to process the chart data request—usually due to high server load, network issues, or timeouts. Superset and Playwright can only wait for the page and chart container to load, but they cannot fix server-side errors; if the API returns a 502 error, the chart will display the error, and a screenshot will record the state. What can I do to address high server load, network issues, etc.?[@dosu](https://go.dosu.dev/dosubot)
GitHub link: https://github.com/apache/superset/discussions/36845#discussioncomment-15349752
----
This is an automatically sent email for notifications@superset.apache.org.
To unsubscribe, please send an email to: notifications-unsubscribe@superset.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org
Re: [D] How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot? [superset]
Posted by "dosubot[bot] (via GitHub)" <gi...@apache.org>.
GitHub user dosubot[bot] added a comment to the discussion: How can I integrate Superset charts with PlayWright to ensure that all charts and data on the page are fully rendered and there are no unexpected errors before taking a screenshot?
<!-- Answer -->
To ensure all Superset charts and data are fully rendered and error-free before taking a screenshot with Playwright in C#, follow the same logic used by Superset's built-in Playwright automation:
1. Navigate to your Superset dashboard or chart URL.
2. Wait for the main container (e.g., `.dashboard` or the relevant class) to appear.
3. Wait for all `.chart-container` elements to be visible.
4. Wait for all `.loading` elements to disappear (state "detached"), which means charts have finished rendering.
5. (Optional) Wait a few seconds for chart animations to complete.
6. Check for error elements with `role="alert"` and extract error messages from `.antd5-modal-content .antd5-modal-body` if present.
7. Take the screenshot.
Here’s a C# Playwright code snippet that implements this logic:
```csharp
using Microsoft.Playwright;
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions { Headless = true });
var page = await browser.NewPageAsync();
await page.GotoAsync("https://your-superset-url/superset/dashboard/123/", new PageGotoOptions { WaitUntil = WaitUntilState.Load });
// Wait for main dashboard container
await page.WaitForSelectorAsync(".dashboard");
// Wait for all chart containers to be visible
var chartContainers = await page.QuerySelectorAllAsync(".chart-container");
foreach (var chart in chartContainers)
{
await chart.WaitForElementStateAsync(ElementState.Visible);
}
// Wait for all loading spinners to disappear
var loadingElements = await page.QuerySelectorAllAsync(".loading");
foreach (var loading in loadingElements)
{
await loading.WaitForElementStateAsync(ElementState.Detached);
}
// Optional: wait for chart animations to finish
await page.WaitForTimeoutAsync(5000);
// Check for unexpected errors
var alerts = await page.QuerySelectorAllAsync("[role='alert']");
foreach (var alert in alerts)
{
var seeMoreBtn = await alert.QuerySelectorAsync("[role='button']");
if (seeMoreBtn != null)
{
await seeMoreBtn.ClickAsync();
var modalBody = await page.QuerySelectorAsync(".antd5-modal-content .antd5-modal-body");
if (modalBody != null)
{
var errorMsg = await modalBody.InnerTextAsync();
// Handle or log errorMsg as needed
}
var closeBtn = await page.QuerySelectorAsync(".antd5-modal-content .antd5-modal-close");
if (closeBtn != null)
await closeBtn.ClickAsync();
await page.WaitForSelectorAsync(".antd5-modal-content", new PageWaitForSelectorOptions { State = WaitForSelectorState.Detached });
}
}
// Take the screenshot
await page.ScreenshotAsync(new PageScreenshotOptions { Path = "dashboard.png" });
```
For large dashboards, consider a tiled screenshot approach: scroll the dashboard in view-sized increments, wait for content to settle after each scroll, and stitch the images together. This is how Superset handles dashboards that extend beyond the viewport [[source]](https://github.com/apache/superset/pull/34561).
You can tune timeouts and delays using Superset config options like `SCREENSHOT_PLAYWRIGHT_DEFAULT_TIMEOUT`, `SCREENSHOT_SELENIUM_ANIMATION_WAIT`, and `SCREENSHOT_SELENIUM_HEADSTART` [[source]](https://github.com/apache/superset/blob/master/superset/config.py).
There are no C#-specific examples in the Superset codebase, but the DOM structure and selectors are the same as in Python, so this approach is portable [[source]](https://github.com/apache/superset/discussions/36839).
<!-- Dosu Comment Footer -->
*To reply, just mention [@dosu](https://go.dosu.dev/dosubot).*
---
<sup>How did I do? [Good](https://app.dosu.dev/response-feedback/eec8805a-0752-4c3a-b1d8-e8ef30ae6c9a?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/eec8805a-0752-4c3a-b1d8-e8ef30ae6c9a?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/eec8805a-0752-4c3a-b1d8-e8ef30ae6c9a?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/eec8805a-0752-4c3a-b1d8-e8ef30ae6c9a?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/eec8805a-0752-4c3a-b1d8-e8ef30ae6c9a?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/eec8805a-0752-4c3a-b1d8-e8ef30ae6c9a?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/eec8805a-0752-4c3a-b1d8-e8ef30ae6c9a?feedback_type=other)</sup>
[](https://app.dosu.dev/a28d3c7e-a9d3-459e-9fb6-3a6f9ff4f357/ask?utm_source=github) [](https://cursor.com/link/prompt?text=To%20ensure%20all%20Superset%20charts%20and%20data%20are%20fully%20rendered%20and%20error-free%20before%20taking%20a%20screenshot%20with%20Playwright%20in%20C%23%2C%20follow%20the%20same%20logic%20used%20by%20Superset%27s%20built-in%20Playwright%20automation%3A%0A%0A1.%20Navigate%20to%20your%20Superset%20dashboard%20or%20chart%20URL.%0A2.%20Wait%20for%20the%20main%20container%20%28e.g.%2C%20%60.dashboard%60%20or%20the%20relevant%20class%29%20to%20appear.%0A3.%20Wait%20for%20all%20%60.chart-container%60%20elements%20to%20be%20visible.%0A4.%20Wait%20for%20all%20%60.loading%60%20elements%20to%20disappear%20%28state%20%22detached%22%29%2C%20which%20means%20charts%20have%20finished%20rendering.%0A5.%20%28Optional%29%20Wait%20a%20few%20seconds%20for%20chart
%20animations%20to%20complete.%0A6.%20Check%20for%20error%20elements%20with%20%60role%3D%22alert%22%60%20and%20extract%20error%20messages%20from%20%60.antd5-modal-content%20.antd5-modal-body%60%20if%20present.%0A7.%20Take%20the%20screenshot.%0A%0AHere%E2%80%99s%20a%20C%23%20Playwright%20code%20snippet%20that%20implements%20this%20logic%3A%0A%0A%60%60%60csharp%0Ausing%20Microsoft.Playwright%3B%0A%0Ausing%20var%20playwright%20%3D%20await%20Playwright.CreateAsync%28%29%3B%0Aawait%20using%20var%20browser%20%3D%20await%20playwright.Chromium.LaunchAsync%28new%20BrowserTypeLaunchOptions%20%7B%20Headless%20%3D%20true%20%7D%29%3B%0Avar%20page%20%3D%20await%20browser.NewPageAsync%28%29%3B%0A%0Aawait%20page.GotoAsync%28%22https%3A//your-superset-url/superset/dashboard/123/%22%2C%20new%20PageGotoOptions%20%7B%20WaitUntil%20%3D%20WaitUntilState.Load%20%7D%29%3B%0A%0A//%20Wait%20for%20main%20dashboard%20container%0Aawait%20page.WaitForSelectorAsync%28%22.dashboard%22%29%3B%0A%0A//%20Wait%20for%20
all%20chart%20containers%20to%20be%20visible%0Avar%20chartContainers%20%3D%20await%20page.QuerySelectorAllAsync%28%22.chart-container%22%29%3B%0Aforeach%20%28var%20chart%20in%20chartContainers%29%0A%7B%0A%20%20%20%20await%20chart.WaitForElementStateAsync%28ElementState.Visible%29%3B%0A%7D%0A%0A//%20Wait%20for%20all%20loading%20spinners%20to%20disappear%0Avar%20loadingElements%20%3D%20await%20page.QuerySelectorAllAsync%28%22.loading%22%29%3B%0Aforeach%20%28var%20loading%20in%20loadingElements%29%0A%7B%0A%20%20%20%20await%20loading.WaitForElementStateAsync%28ElementState.Detached%29%3B%0A%7D%0A%0A//%20Optional%3A%20wait%20for%20chart%20animations%20to%20finish%0Aawait%20page.WaitForTimeoutAsync%285000%29%3B%0A%0A//%20Check%20for%20unexpected%20errors%0Avar%20alerts%20%3D%20await%20page.QuerySelectorAllAsync%28%22%5Brole%3D%27alert%27%5D%22%29%3B%0Aforeach%20%28var%20alert%20in%20alerts%29%0A%7B%0A%20%20%20%20var%20seeMoreBtn%20%3D%20await%20alert.QuerySelectorAsync%28%22%5Brole%3D%27b
utton%27%5D%22%29%3B%0A%20%20%20%20if%20%28seeMoreBtn%20%21%3D%20null%29%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20await%20seeMoreBtn.ClickAsync%28%29%3B%0A%20%20%20%20%20%20%20%20var%20modalBody%20%3D%20await%20page.QuerySelectorAsync%28%22.antd5-modal-content%20.antd5-modal-body%22%29%3B%0A%20%20%20%20%20%20%20%20if%20%28modalBody%20%21%3D%20null%29%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20errorMsg%20%3D%20await%20modalBody.InnerTextAsync%28%29%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20//%20Handle%20or%20log%20errorMsg%20as%20needed%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20var%20closeBtn%20%3D%20await%20page.QuerySelectorAsync%28%22.antd5-modal-content%20.antd5-modal-close%22%29%3B%0A%20%20%20%20%20%20%20%20if%20%28closeBtn%20%21%3D%20null%29%0A%20%20%20%20%20%20%20%20%20%20%20%20await%20closeBtn.ClickAsync%28%29%3B%0A%20%20%20%20%20%20%20%20await%20page.WaitForSelectorAsync%28%22.antd5-modal-content%22%2C%20new%20PageWaitForSelecto
rOptions%20%7B%20State%20%3D%20WaitForSelectorState.Detached%20%7D%29%3B%0A%20%20%20%20%7D%0A%7D%0A%0A//%20Take%20the%20screenshot%0Aawait%20page.ScreenshotAsync%28new%20PageScreenshotOptions%20%7B%20Path%20%3D%20%22dashboard.png%22%20%7D%29%3B%0A%60%60%60%0A%0AFor%20large%20dashboards%2C%20consider%20a%20tiled%20screenshot%20approach%3A%20scroll%20the%20dashboard%20in%20view-sized%20increments%2C%20wait%20for%20content%20to%20settle%20after%20each%20scroll%2C%20and%20stitch%20the%20images%20together.%20This%20is%20how%20Superset%20handles%20dashboards%20that%20extend%20beyond%20the%20viewport%20%5B%5Bsource%5D%5D%28https%3A//github.com/apache/superset/pull/34561%29.%0A%0AYou%20can%20tune%20timeouts%20and%20delays%20using%20Superset%20config%20options%20like%20%60SCREENSHOT_PLAYWRIGHT_DEFAULT_TIMEOUT%60%2C%20%60SCREENSHOT_SELENIUM_ANIMATION_WAIT%60%2C%20and%20%60SCREENSHOT_SELENIUM_HEADSTART%60%20%5B%5Bsource%5D%5D%28https%3A//github.com/apache/superset/blob/master/superset/config.p
y%29.%0A%0AThere%20are%20no%20C%23-specific%20examples%20in%20the%20Superset%20codebase%2C%20but%20the%20DOM%20structure%20and%20selectors%20are%20the%20same%20as%20in%20Python%2C%20so%20this%20approach%20is%20portable%20%5B%5Bsource%5D%5D%28https%3A//github.com/apache/superset/discussions/36839%29.) [](https://go.dosu.dev/discord-bot) [](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/apache/superset/discussions/36845)
GitHub link: https://github.com/apache/superset/discussions/36845#discussioncomment-15349414
----
This is an automatically sent email for notifications@superset.apache.org.
To unsubscribe, please send an email to: notifications-unsubscribe@superset.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org