-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Screenshotting] Fix potential race condition when screenshotting #123820
[Screenshotting] Fix potential race condition when screenshotting #123820
Conversation
return driver | ||
.setViewport(viewport, this.logger) | ||
.then(() => | ||
waitForVisualizations(driver, this.logger, waitTimeout, itemsCount, this.layout) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, I've just a side note, not related to this PR but something that can be considered in the future to improve the rendering time: what about considering setting the viewport before opening the page? this will skip at least 1 rendering cycle to resize all the visualizations. We can probably get this information from the URL and/or the saved object related to that dashboard/viz.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @markov00 ! That's a great idea. I was thinking we might have to do something a bit more complicated (like inject a resize observer) to really know when the reflow is done 😅 . Your suggestion sounds a lot simpler and definitely worth looking into.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems the reason we do this here is because this is the point where we know how many items there are to render. For print layout, we have to know the number of items to resize the viewport: https://github.com/elastic/kibana/blob/main/x-pack/plugins/screenshotting/server/layouts/print_layout.ts#L47
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For a later PR perhaps: let's consider making this whole mergeMap conditional, and used only if the report job is the "optimized for print" layout mode.
if (this.layout.id === LayoutTypes.PRINT) {
// set the viewport to the dimentions from the job, to allow elements to flow into print-optimized layout
const viewport = this.layout.getViewport(itemsCount) || getDefaultViewPort();
await driver.setViewport(viewport, this.logger);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point @tsullivan , it looks like the resize is for height in that case so I think we should at least be able to address a "width" reflow which seems could be more problematic.
I'll open up an issue to capture your suggested change!
@elasticmachine merge upstream |
merge conflict between base and head |
…fix-potential-race-condition-when-screenshotting * 'main' of github.com:elastic/kibana: (75 commits) [Reporting] Logging improvements while generating reports (elastic#123802) [Uptime] Default alert connectors email settings (elastic#123244) Update comparison series styles to match the main series (elastic#123858) [RAC][Uptime] remove extra dot from the uptime alert connector message (elastic#124000) [Exploratory view] Allow ability add extra actions in lens embeddable (elastic#123713) [SecuritySolution][Investigations] Add message about missing index in data view in analyzer (elastic#122859) [TSVB] Formatting in the left axis is not respected when I have two separate axis (elastic#123903) [Discover] Remove services from component dependencies (elastic#121691) Stop IM rule execution if there are no events (elastic#123811) [Security Solution][Endpoint] Update Fleet Trusted Apps and Host Isolation Exception cards to use exception list summary API (elastic#123900) [Security Solution][Exceptions] Switches modal to flyout component (elastic#123408) [Workplace Search] Fix bug where modal visible after deleting a group (elastic#123976) [Alerting] Remove state variables from action variable menu (elastic#123702) replace deprecated api usage (elastic#123970) Fix package policy merge logic for boolean values (elastic#123974) [Security Solution][Endpoint][Policy] Remove GET policy list api route (elastic#123873) Reenable alert_add test suite (elastic#123862) [Fleet] Remove usage of IFieldType in Fleet (elastic#123960) [Lists] Add an instance of `ExceptionListClient` with server extension points turned off to context object provided to callbacks (elastic#123885) [Maps] Add execution context (elastic#123651) ... # Conflicts: # x-pack/plugins/screenshotting/server/browsers/chromium/driver_factory/index.ts
… viewport for every page that is created
… have a "undefined" set as a key value
@elasticmachine merge upstream |
…when-screenshotting
Pinging @elastic/kibana-reporting-services (Team:Reporting Services) |
Pinging @elastic/kibana-app-services (Team:AppServicesUx) |
@elasticmachine merge upstream |
…when-screenshotting
@elasticmachine merge upstream |
…when-screenshotting
…when-screenshotting
@elasticmachine merge upstream |
…when-screenshotting
@elasticmachine merge upstream |
…when-screenshotting
// browser reflow. In most cases only the height needs to be adjusted | ||
// before taking a screenshot. | ||
// NOTE: _.defaults assigns to the target object, so we copy it. | ||
defaultViewport: _.defaults({ ...defaultViewport }, DEFAULT_VIEWPORT), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason why this can't be just:
defaultViewport: _.defaults({ ...defaultViewport }, DEFAULT_VIEWPORT), | |
defaultViewport: { ...DEFAULT_VIEWPORT, ...defaultViewport }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason I chose _.defaults
is because the override behaviour is different with own props (it ignores overrides that are undefined
, so we won't end up with width: undefined
for ex.).
Do you think we should change the type of defaultViewport
making both width
and height
required values? I see they are both required in the Size
object. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested this locally, and it looks like height
can currently be undefined when passing it directly from layout.height
to the createPage
call resulting in this error:
[2022-02-07T10:36:53.499+01:00][INFO ][plugins.reporting.runTask.printablePdfV2.printable_pdf_v2.execute-job.kzci20um17zm9d0062eb528s] Compiling PDF using "preserve_layout" layout...
[2022-02-07T10:36:55.542+01:00][INFO ][plugins.reporting.runTask] Saved printable_pdf_v2 job /.reporting-2022-02-06/_doc/kzci20um17zm9d0062eb528s
[2022-02-07T10:36:59.710+01:00][INFO ][plugins.screenshotting.screenshot.browser-driver] Creating browser page driver
Unhandled Promise rejection detected:
Error: Protocol error (Emulation.setDeviceMetricsOverride): Invalid parameters Failed to deserialize params.height - BINDINGS: mandatory field missing at position 88
at /Users/jeanlouisleysens/repos/work/kibana/node_modules/puppeteer/src/common/Connection.ts:291:57
at new Promise (<anonymous>)
at CDPSession.send (/Users/jeanlouisleysens/repos/work/kibana/node_modules/puppeteer/src/common/Connection.ts:290:12)
at EmulationManager.emulateViewport (/Users/jeanlouisleysens/repos/work/kibana/node_modules/puppeteer/src/common/EmulationManager.ts:41:20)
at Page.setViewport (/Users/jeanlouisleysens/repos/work/kibana/node_modules/puppeteer/src/common/Page.ts:2383:54)
at Function.create (/Users/jeanlouisleysens/repos/work/kibana/node_modules/puppeteer/src/common/Page.ts:444:37)
at runMicrotasks (<anonymous>)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at Browser._createPageInContext (/Users/jeanlouisleysens/repos/work/kibana/node_modules/puppeteer/src/common/Browser.ts:468:18)
at Observable._subscribe (/Users/jeanlouisleysens/repos/work/kibana/x-pack/plugins/screenshotting/server/browsers/chromium/driver_factory/index.ts:125:20)
I think, for now, we can leave this default using the lodash algo. WDYT?
/** | ||
* We naively round all numeric values in the object, this will break screenshotting | ||
* if ever a have a non-number set as a value, but this points to an issue | ||
* in the code responsible for creating the dimensions object. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would it be possible to have a unit test that explores this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, I think we could, but it may need to be a funcitonal test because the "break" occurs when we pass any non integer value to Chromium when launching (so floats or NaN would break it).
Is that the kind of test you had in mind?
@@ -36,6 +37,12 @@ import { getMetrics, PerformanceMetrics } from './metrics'; | |||
|
|||
interface CreatePageOptions { | |||
browserTimezone?: string; | |||
defaultViewport?: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be a required property instead of optional? It looks like the only area it's not given is in tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, let's do that! I'll also make both height
and width
required values!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great! If it doesn't impact anything (existing POST URLs?), it would make things more clear.
@elasticmachine merge upstream |
return driver | ||
.setViewport(viewport, this.logger) | ||
.then(() => | ||
waitForVisualizations(driver, this.logger, waitTimeout, itemsCount, this.layout) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return driver | |
.setViewport(viewport, this.logger) | |
.then(() => | |
waitForVisualizations(driver, this.logger, waitTimeout, itemsCount, this.layout) | |
); | |
await driver.setViewport(viewport, this.logger) | |
await waitForVisualizations(driver, this.logger, waitTimeout, itemsCount, this.layout); |
@elasticmachine merge upstream |
Hey @dokmic and @tsullivan I think I've addressed all your feedback. Do you think you could take another look? |
💚 Build SucceededMetrics [docs]
History
To update your PR or re-run it, just comment with: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Great job 👍
@tsullivan happy to return to this in a follow up PR #123820 (comment)! Let me know what you think, I decided to merge this in the meantime. |
…astic#123820) * extract message from error objects * only warn for 400 and up status codes * naively wait for vis ready after resizing the browser viewport * use a single default viewport size, enable layout to set default page viewport for every page that is created * refactor viewport -> windowSize in chromium args * allow overriding defaults and use new windowSize arg for chromium args * always round page dimension numbers. note: this will break if we ever have a "undefined" set as a key value * added comment * update snapshot to new width value * make defaultViewport a required field on createPage * added comment * style: use async-await rather than .then chaining. also added a comment Co-authored-by: Kibana Machine <[email protected]> (cherry picked from commit b2b60ff)
…astic#123820) * extract message from error objects * only warn for 400 and up status codes * naively wait for vis ready after resizing the browser viewport * use a single default viewport size, enable layout to set default page viewport for every page that is created * refactor viewport -> windowSize in chromium args * allow overriding defaults and use new windowSize arg for chromium args * always round page dimension numbers. note: this will break if we ever have a "undefined" set as a key value * added comment * update snapshot to new width value * make defaultViewport a required field on createPage * added comment * style: use async-await rather than .then chaining. also added a comment Co-authored-by: Kibana Machine <[email protected]> (cherry picked from commit b2b60ff)
…23820) (#125055) * extract message from error objects * only warn for 400 and up status codes * naively wait for vis ready after resizing the browser viewport * use a single default viewport size, enable layout to set default page viewport for every page that is created * refactor viewport -> windowSize in chromium args * allow overriding defaults and use new windowSize arg for chromium args * always round page dimension numbers. note: this will break if we ever have a "undefined" set as a key value * added comment * update snapshot to new width value * make defaultViewport a required field on createPage * added comment * style: use async-await rather than .then chaining. also added a comment Co-authored-by: Kibana Machine <[email protected]> (cherry picked from commit b2b60ff)
…23820) (#125054) * extract message from error objects * only warn for 400 and up status codes * naively wait for vis ready after resizing the browser viewport * use a single default viewport size, enable layout to set default page viewport for every page that is created * refactor viewport -> windowSize in chromium args * allow overriding defaults and use new windowSize arg for chromium args * always round page dimension numbers. note: this will break if we ever have a "undefined" set as a key value * added comment * update snapshot to new width value * make defaultViewport a required field on createPage * added comment * style: use async-await rather than .then chaining. also added a comment Co-authored-by: Kibana Machine <[email protected]> (cherry picked from commit b2b60ff)
Summary
Closes #122391
We reduce unnecessary reflow by:
How to test
Manually test creating a visual report for:
In all cases check that the resulting report looks as expected.
Notes