Skip to content
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

[Search] Fix dashboard embeddables don't refetch on searchSessionId change #84261

Merged
merged 11 commits into from
Dec 10, 2020

Conversation

Dosant
Copy link
Contributor

@Dosant Dosant commented Nov 24, 2020

Summary

Part of #83640

Fixes a bug on a dashboard with session indicator, that, for example, when switching from view to edit, session indicator disappears:

Dec-02-2020 12-15-22

Now in master, on any dashboard container state change new search session is started, but inner embeddables "dirty" state checking don't check for sessionId changes, so embeddable don't refetch the data.
Because there is new session and no searches are fired, session indicator gets into "empty" state and is not shown.

This pr makes search, visualize and lens embeddables (only those support searchSessionId for now) to check if searchSessionId is changed and if it is, then do refetch.

To not trigger data refetch on any dashboard container state change, there is also a new optimization inside dashboard to not create a new session on every state change: https://github.com/elastic/kibana/pull/84261/files#diff-d4d5bed484b46a4b7df6cd2d09b106bd761c956c53df96f8da6e683901475156R636

In an original pr which added searchSessionId I initially triggered refetch on searchSessionId change, but reverted because of this edge case: #81297 (comment)
Basically, when refetch is triggered on searchSesssionId hitting refresh caused double fetches for each embeddable:
When refresh is hit lastReloadRequestTime and searchSesssionId were updated, then onResetInput updated embeddable input and then called force reload: https://github.com/elastic/kibana/blob/master/src/plugins/embeddable/public/lib/embeddables/embeddable.tsx#L206
It caused embeddable to fetch twice: once because of updated input and searchSesssionId change and then because of force reload
To workaround this (not very happy with the workaround, open for better ideas) I introduced getUpdated$ observable https://github.com/elastic/kibana/pull/84261/files#diff-07c6d43a257e24b0d89b752078b298591b28d74047ddc44a38f35d130958a25dR126 which is different from merge(getInput$(), getOutput$()) that is

  1. debounces input/output updates allowing to react only once if input/output changes synchronously (not really relevant for this workaround, but this is a nice nit optimization)
  2. delays emit to next macrotask.
    This observable allows for embeddables to first react to force reload with the latest input/output and later when getUpdated$() is emitted embeddable dirty state checking will prevent running fetch again.

How to test

xpack.data_enhanced.search.sendToBackground.enabled: true
data.search.aggs.shardDelay.enabled: true # helpful to create "slow" visualizations
  1. Background session indicator shouldn't disappear when switching from dashboard view modes or doing other non-search result relevant change
  2. Embeddable shouldn't try to refetch data twice on state changes or when hitting refresh

Checklist

Delete any items that are not applicable to this PR.

For maintainers

@Dosant Dosant mentioned this pull request Dec 1, 2020
38 tasks
# Conflicts:
#	src/plugins/discover/public/application/embeddable/search_embeddable.ts
@Dosant Dosant force-pushed the dev/search/dashboard-start-session-fix branch from 242fcc2 to b268407 Compare December 2, 2020 10:39
@Dosant Dosant changed the title [wip] Dev/search/dashboard start session fix [Search] Fix dashboard embeddable refetches on sessionId changes Dec 2, 2020
@@ -245,16 +253,9 @@ export class Embeddable
};

async reload() {
const currentTime = Date.now();
if (this.externalSearchContext.lastReloadRequestTime !== currentTime) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am either missing something or I think this check didn't make sense, because I'd expect Date.now() on line above to always return later timestamp that is saved inside lastReloadRequestTime.

I decided to clean this up, pls let me know if this was actually handling some edge case

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it was put in place to protect from multiple synchronous reload calls, but I didn't find a case where that's a problem. It's fine from my side.

@Dosant Dosant changed the title [Search] Fix dashboard embeddable refetches on sessionId changes [Search] Fix dashboard embeddables don't refetch on sessionId change Dec 2, 2020
@Dosant Dosant changed the title [Search] Fix dashboard embeddables don't refetch on sessionId change [Search] Fix dashboard embeddables don't refetch on searchSessionId change Dec 2, 2020
@Dosant Dosant marked this pull request as ready for review December 2, 2020 12:36
@Dosant Dosant requested a review from a team December 2, 2020 12:36
@Dosant Dosant requested review from a team as code owners December 2, 2020 12:36
@Dosant Dosant added bug Fixes for quality problems that affect the customer experience Feature:Embedding Embedding content via iFrame Feature:Search Querying infrastructure in Kibana release_note:skip Skip the PR/issue when compiling release notes Team:AppServices v7.11.0 v8.0.0 labels Dec 2, 2020
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-app-services (Team:AppServices)

@Dosant Dosant added the Feature:Dashboard Dashboard related features label Dec 2, 2020
@Dosant
Copy link
Contributor Author

Dosant commented Dec 3, 2020

@elasticmachine merge upstream

Copy link
Contributor

@ThomThomson ThomThomson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally don't have a problem at all with the workaround of adding a getUpdated$ observable. Anything that helps standardize how embeddables respond to changes is good in my books.

When testing locally, I verified embeddables only fire one network request on refresh, filter change & time range change. The background sessions indicator is also always present now.

One thing I did notice is that the dashboard is reloaded now on 'cancel' when you choose to discard changes. This wasn't the case before, as nothing is changing that would require a re-fetch. Is this intended?

Copy link
Contributor

@flash1293 flash1293 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested the Lens part and seems to work fine

@@ -245,16 +253,9 @@ export class Embeddable
};

async reload() {
const currentTime = Date.now();
if (this.externalSearchContext.lastReloadRequestTime !== currentTime) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it was put in place to protect from multiple synchronous reload calls, but I didn't find a case where that's a problem. It's fine from my side.

@@ -110,7 +110,9 @@ export class Embeddable

this.expressionRenderer = deps.expressionRenderer;
this.initializeSavedVis(initialInput).then(() => this.onContainerStateChanged(initialInput));
this.subscription = this.getInput$().subscribe((input) => this.onContainerStateChanged(input));
this.subscription = this.getUpdated$().subscribe(() =>
this.onContainerStateChanged(this.input)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Should this.input be used? There's also this.getInput() which is used in other places. Not sure whether important, just wanted to point it out.

Copy link
Contributor Author

@Dosant Dosant Dec 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this.getInput() is public and this.input is protected, so I guess inside the embeddable it is fine to use both

@Dosant
Copy link
Contributor Author

Dosant commented Dec 8, 2020

@ThomThomson,

One thing I did notice is that the dashboard is reloaded now on 'cancel' when you choose to discard changes. This wasn't the case before, as nothing is changing that would require a re-fetch. Is this intended?

Good catch.

If you "discard changes" and there is no change in state keys that cause starting a new session, then no refetch would happen. e.g. when just switching between view -> edit -> (discard) -> view mode.

But in general with this change we are triggering a refetch more often then we had before.
For example, we would refetch in case any change to panels happens (because we are starting a new session).

This fixes following bug @lukasolson pointed out:

Looks like there’s a bit of a bug when you wait until all the results have loaded, then add a new panel (which will only cause the new panel to fetch data), then send to background. If you restore, only the newest panel will actually restore properly


But in general with this change we are triggering a refetch more often then we had before.

I think we have to accept this drawback for now with current session management design :(
@lukasolson, probably we could avoid this excessive refetches if we introduce a way to "extend" a session (like clone and add more async searches to it)

@lizozom
Copy link
Contributor

lizozom commented Dec 8, 2020

@Dosant there shouldn't be a problem with adding a new request to the current session, in this new panel scenario.
We could "re-open" it, and I think everything should still work.

Copy link
Contributor

@lizozom lizozom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested the following

  • Switching to edit mode - doesn't clear session
  • Cancel back to view mode - doesn't clear session
  • Fullscreen - doesn't clear session
  • Delete a panel from a dashboard - doesn't clear session
  • Moving a panel and saving - doesn't clear session
  • Adding a panel and saving - doesn't clear session

When a sesison is not cleared, it means items are added to the existing session, which I find reasonable.

LGTM

@Dosant
Copy link
Contributor Author

Dosant commented Dec 8, 2020

@Dosant there shouldn't be a problem with adding a new request to the current session, in this new panel scenario.
We could "re-open" it, and I think everything should still work.

@ThomThomson, would you be OK if I create an issue for this excessive fetches we gonna track and look into improving if/when we add this re-open API @lizozom mentions?

---- edit

created: #85293

Copy link
Contributor

@ThomThomson ThomThomson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With an issue for awareness around the excessive fetches I am good to approve this. Hopefully there will be a fix, but if this is just the way the session service works it's not too bad a change anyway.

@Dosant
Copy link
Contributor Author

Dosant commented Dec 9, 2020

@elasticmachine merge upstream

@Dosant
Copy link
Contributor Author

Dosant commented Dec 9, 2020

@kertal, although this got all code owners review, search embeddable still needs a 👀 🙏

@kertal
Copy link
Member

kertal commented Dec 10, 2020

@Dosant ACK, yes, thx, will have a look today

@Dosant
Copy link
Contributor Author

Dosant commented Dec 10, 2020

@elasticmachine merge upstream

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
dashboard 197.0KB 197.2KB +248.0B
discover 450.3KB 450.4KB +187.0B
lens 1011.8KB 1011.8KB +4.0B
total +439.0B

Distributable file count

id before after diff
default 46990 47750 +760

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
embeddable 225.7KB 226.1KB +394.0B
visualizations 169.0KB 168.9KB -148.0B
total +246.0B

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

Copy link
Member

@kertal kertal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code LGTM, mainly took a look at the search embeddable and it's fetching behavior, recently fixed a double fetch there, so the good news after testing locally: it fetches when it should, no less, no more 👍

@Dosant Dosant merged commit cb29438 into elastic:master Dec 10, 2020
Dosant added a commit to Dosant/kibana that referenced this pull request Dec 10, 2020
ThomThomson added a commit to ThomThomson/kibana that referenced this pull request Dec 10, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Fixes for quality problems that affect the customer experience Feature:Dashboard Dashboard related features Feature:Embedding Embedding content via iFrame Feature:Search Querying infrastructure in Kibana release_note:skip Skip the PR/issue when compiling release notes v7.11.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants