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] Session SO polling #84225

Merged
merged 44 commits into from
Dec 9, 2020
Merged

Conversation

lizozom
Copy link
Contributor

@lizozom lizozom commented Nov 24, 2020

Summary

Blocked by #84837

This PR introduces session polling: each Kibana server tracks search IDS in memory and checks whether a matching Background Session was created for each . If it was, search IDs are synced into the SO and cleared from memory.

This PR handles search expiration, version conflicts and max retries.
This code is enabled only if the dev feature flag is on!!!

Checklist

Delete any items that are not applicable to this PR.

For maintainers

#84837

@lizozom
Copy link
Contributor Author

lizozom commented Nov 30, 2020

@elasticmachine merge upstream

@kibanamachine
Copy link
Contributor

merge conflict between base and head

@lizozom lizozom marked this pull request as ready for review November 30, 2020 18:00
@lizozom lizozom requested review from a team as code owners November 30, 2020 18:00
@lizozom lizozom self-assigned this Nov 30, 2020
@lizozom lizozom requested a review from a team as a code owner November 30, 2020 18:00
@lizozom lizozom added v7.11.0 v8.0.0 release_note:skip Skip the PR/issue when compiling release notes Team:AppArch labels Nov 30, 2020
@lukasolson lukasolson self-requested a review November 30, 2020 18:50
Copy link
Contributor

@jportner jportner left a comment

Choose a reason for hiding this comment

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

Code review only: Spaces changes (unit test mocks) LGTM!

Copy link
Member

@legrego legrego left a comment

Choose a reason for hiding this comment

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

A couple of preliminary questions for you -- I haven't had a chance to pull this down to run it, so I'm sorry for the lack of concrete guidance right now. I'll update my comments with suggestions once I have a chance to run this locally

src/plugins/data/server/search/session/session_service.ts Outdated Show resolved Hide resolved
src/plugins/data/server/search/session/session_service.ts Outdated Show resolved Hide resolved
@legrego legrego self-requested a review December 1, 2020 19:42
@legrego
Copy link
Member

legrego commented Dec 1, 2020

I started leaving some comments, but I'm a little confused. We previously said (IIRC) in the RFC that these sessions would be space-aware, and the saved object that represents the session indicates this. However, the entire BackgroundSessionService is using these saved objects as if they are not space-aware. All sessions are being stored within the default space, even if they belong to a different space.

So, I guess I'm asking: should background sessions be space-aware, or space-agnostic? If Space-aware, then we need to re-work the BackgroundSessionService to actually be space-aware. If Space-agnostic, then the Saved Object definition for this type is incorrect.

@lizozom lizozom changed the title [Search] Session monitoring [Search] Session SO polling Dec 7, 2020
Copy link
Member

@legrego legrego left a comment

Choose a reason for hiding this comment

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

I haven't tested yet, but this looks much better! Thanks for taking the time to make this space-aware

const res = await this.internalSavedObjectsClient.find<BackgroundSessionSavedObjectAttributes>({
type: BACKGROUND_SESSION_TYPE,
search: activeMappingIds,
searchFields: ['sessionId'],
Copy link
Member

Choose a reason for hiding this comment

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

Using searchFields to search for exact matches has proved problematic for other teams (Alerting and ML come to mind).

Have you explored using a KQL filter for this? The alerting team builds theirs programmatically to retrieve documents matching specific criteria:
https://github.com/elastic/kibana/blob/223a18766ad4bc079d461ef145e9b2e3e9fa2469/x-pack%2Fplugins%2Falerts%2Fserver%2Fauthorization%2Falerts_authorization_kuery.ts

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Created an issue for this #85252

};

public asScopedProvider = ({ savedObjects }: CoreStart) => {
return (request: KibanaRequest) => {
Copy link
Member

Choose a reason for hiding this comment

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

👍 Thanks for introducing the scoped provider.

Since we haven't granted any privileges for this new saved object type, these requests will all fail our authorization checks unless the user is a superuser.

I know we're discussing background session security outside of this PR, but I wanted to raise it anyway in case this wasn't your expectation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So how should this be correctly addressed?

Copy link
Member

Choose a reason for hiding this comment

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

We'll either take the sub-feature privilege approach, or the top-level feature approach that we've been discussing in the doc that Brandon put together. Once we reach consensus I'll help you with the changes that we'll need to make

);
}

// TODO: Generate the `userId` from the realm type/realm name/username
Copy link
Member

Choose a reason for hiding this comment

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

Check with us before doing so. We are working with the ES security team to come up with a unique user identifier that doesn't rely on the realm name.

return session;
};

// TODO: Throw an error if this session doesn't belong to this user
Copy link
Member

Choose a reason for hiding this comment

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

Not sure what your timeline looks like, but we are starting work on OLS Phase 1, which might prove useful here.

Copy link
Member

Choose a reason for hiding this comment

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

@legrego We have a PR up already, would you mind taking a look? #84975

Copy link
Member

@lukasolson lukasolson left a comment

Choose a reason for hiding this comment

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

Overall, this LGTM, just a few minor things you can take or leave below. Tested and things seem to be working. I created a terms agg other bucket with a delay of 30s (30s for the initial request and 30s for the follow-up request), then sent to background before the first request completed. I stayed on the page for the second request to be initiated, and behind the scenes the SO was updated properly, and restoring it worked.

// Get the mapping of request hash/search ID for this session
const searchMap = this.sessionSearchMap.get(sessionId) ?? new Map<string, string>();
const idMapping = Object.fromEntries(searchMap.entries());
Copy link
Member

Choose a reason for hiding this comment

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

Is your thinking just that we might as well only do the updating in the monitoring task rather than here as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes!I think it's best if all updates are done from one place (we also need to be extending expiration in the monitoring task)

Copy link
Contributor

Choose a reason for hiding this comment

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

If my understanding correct, then after saving a background search worst case all relevant searches will be pushed to this object in 10s?

Wouldn't it lead to weird race condition where user navigates to background session management and experiences incorrect state? Or tries to restores searches before monitoring loop pushed them to SO? This especially could cause flakiness in e2e tests where everything is fast and non deterministic.

},
});

const router = core.http.createRouter();
registerSessionRoutes(router);
}

public start(core: CoreStart) {}
public start(core: CoreStart) {
this.sessionService.start(core, this.initializerContext.config.create());
Copy link
Member

Choose a reason for hiding this comment

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

At some point, should we make SessionService and BackgroundSessionService actual services (that implement Plugin)? Doesn't need to be part of this PR, just my thoughts.

import { createRequestHash } from './utils';
import moment from 'moment';
Copy link
Member

Choose a reason for hiding this comment

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

Nit: I don't think we're doing anything all that complicated with moment in this file other than a couple of date comparisons. In general, I think we should avoid bringing in libraries for these sorts of trivial operations.

Copy link
Contributor Author

@lizozom lizozom Dec 8, 2020

Choose a reason for hiding this comment

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

We already use moment in the data plugin, so I don't think it should matter. :)
And as the code uses them , I needed the types to match. No?

Copy link
Contributor

@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.

my 5 cents: I'd also not used moment for this.
Seems like nothing complicated that requires moment, but for me makes harder to reason about and read the code than if it was with regular Date.now.
For example:

curTime.diff(sessionInfo.insertTime)

I don't know if this returns curTime - insertTime or insertTime - curTime without looking into docs

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'd have to use this kind of syntax: new Date(new Date().getTime() - (2*60*1000)); rather than moment().subtract(2, 'm').
I'm really not a fan, but if you insist 🤷

Copy link
Contributor

Choose a reason for hiding this comment

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

nit a bit shorter: new Date(Date.now() - (2601000));

One q: are there timezones risks in play? Maybe movement handles something in addition related to tz?

import { createRequestHash } from './utils';
import moment from 'moment';
Copy link
Contributor

@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.

my 5 cents: I'd also not used moment for this.
Seems like nothing complicated that requires moment, but for me makes harder to reason about and read the code than if it was with regular Date.now.
For example:

curTime.diff(sessionInfo.insertTime)

I don't know if this returns curTime - insertTime or insertTime - curTime without looking into docs

// Get the mapping of request hash/search ID for this session
const searchMap = this.sessionSearchMap.get(sessionId) ?? new Map<string, string>();
const idMapping = Object.fromEntries(searchMap.entries());
Copy link
Contributor

Choose a reason for hiding this comment

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

If my understanding correct, then after saving a background search worst case all relevant searches will be pushed to this object in 10s?

Wouldn't it lead to weird race condition where user navigates to background session management and experiences incorrect state? Or tries to restores searches before monitoring loop pushed them to SO? This especially could cause flakiness in e2e tests where everything is fast and non deterministic.

Copy link
Contributor

@Dosant Dosant left a comment

Choose a reason for hiding this comment

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

Should we add retry mechanism for this snippet in case we retrieved a session but there is yet no searches with that hash?

const session = await this.get(sessionId, deps);
const requestHash = createRequestHash(searchRequest.params);
if (!session.attributes.idMapping.hasOwnProperty(requestHash)) {
throw new Error('No search ID in this session matching the given search request');
}

…vice.ts

Co-authored-by: Anton Dosov <dosantappdev@gmail.com>
return sessionSavedObject;
});

const updateResults = await this.internalSavedObjectsClient.bulkUpdate<BackgroundSessionSavedObjectAttributes>(
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if this could throw a conflict error and if we should immediately retry if it did. (I am not sure when SO api throws conflict error, just've seen 409 error before)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As far as I understand, bulkUpdate returns an error per object. You can see those processed in monitorMappedIds, when checking each response item for errors.

Copy link
Contributor

@Dosant Dosant left a comment

Choose a reason for hiding this comment

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

lgtm, didn't test.
re-reviewed interval -> timeout change

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Saved Objects .kibana field count

Every field in each saved object type adds overhead to Elasticsearch. Kibana needs to keep the total field count below Elasticsearch's default limit of 1000 fields. Only specify field mappings for the fields you wish to search on or query. See https://www.elastic.co/guide/en/kibana/master/development-plugin-saved-objects.html#_mappings

id before after diff
background-session 7 8 +1

History

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

@lizozom lizozom merged commit 0a04835 into elastic:master Dec 9, 2020
lizozom added a commit to lizozom/kibana that referenced this pull request Dec 9, 2020
* Monitor ids

* import fix

* solve circular dep

* eslint

* mock circular dep

* max retries test

* mock circular dep

* test

* jest <(-:C

* jestttttt

* [data.search] Move search method inside session service and add tests

* merge

* Move background session service to data_enhanced plugin

* Better logs
Save IDs only in monitoring loop

* Fix types

* Space aware session service

* ts

* Fix session service saving

* merge fix

* stable stringify

* INMEM_MAX_SESSIONS

* INMEM_MAX_SESSIONS

* Update x-pack/plugins/data_enhanced/server/search/session/session_service.ts

Co-authored-by: Anton Dosov <dosantappdev@gmail.com>

* Update x-pack/plugins/data_enhanced/server/search/session/session_service.ts

Co-authored-by: Anton Dosov <dosantappdev@gmail.com>

* Use setTimeout to schedule monitoring steps

* settimeout

Co-authored-by: Lukas Olson <olson.lukas@gmail.com>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Anton Dosov <dosantappdev@gmail.com>
jloleysens added a commit to jloleysens/kibana that referenced this pull request Dec 9, 2020
…k-field-to-hot-phase

* 'master' of github.com:elastic/kibana: (429 commits)
  simplify popover open state logic (elastic#85379)
  [Logs UI][Metrics UI] Move actions to the kibana header (elastic#84648)
  [Search Source] Do not pick scripted fields if * provided (elastic#85133)
  [Search] Session SO polling (elastic#84225)
  [Transform] Replace legacy elasticsearch client (elastic#84932)
  [Uptime]Refactor header and action menu (elastic#83779)
  Fix agg select external link (elastic#85380)
  [ILM] Show forcemerge in hot when rollover is searchable snapshot is enabled (elastic#85292)
  clear using keyboard (elastic#85042)
  [GS] add tag and dashboard suggestion results (elastic#85144)
  [ML] API integration tests - skip GetAnomaliesTableData
  Add ECS field for event.code. (elastic#85109)
  [Functional][TSVB] Wait for markdown textarea to be cleaned (elastic#85128)
  skip flaky suite (elastic#62060)
  skip flaky suite (elastic#85098)
  Bump highlight.js to v9.18.5 (elastic#84296)
  Add `server.publicBaseUrl` config (elastic#85075)
  [Alerting & Actions ] More debug logging (elastic#85149)
  [Security Solution][Case] Manual attach alert to a case (elastic#82996)
  Loosen UUID regex to accept uuidv1 or uuidv4 (elastic#85338)
  ...

# Conflicts:
#	x-pack/plugins/index_lifecycle_management/__jest__/client_integration/edit_policy/edit_policy.helpers.tsx
#	x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/hot_phase/hot_phase.tsx
#	x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/shared_fields/index.ts
#	x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/phases/warm_phase/warm_phase.tsx
#	x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx
#	x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/i18n_texts.ts
#	x-pack/plugins/index_lifecycle_management/server/routes/api/policies/register_create_route.ts
lizozom added a commit that referenced this pull request Dec 9, 2020
* Monitor ids

* import fix

* solve circular dep

* eslint

* mock circular dep

* max retries test

* mock circular dep

* test

* jest <(-:C

* jestttttt

* [data.search] Move search method inside session service and add tests

* merge

* Move background session service to data_enhanced plugin

* Better logs
Save IDs only in monitoring loop

* Fix types

* Space aware session service

* ts

* Fix session service saving

* merge fix

* stable stringify

* INMEM_MAX_SESSIONS

* INMEM_MAX_SESSIONS

* Update x-pack/plugins/data_enhanced/server/search/session/session_service.ts

Co-authored-by: Anton Dosov <dosantappdev@gmail.com>

* Update x-pack/plugins/data_enhanced/server/search/session/session_service.ts

Co-authored-by: Anton Dosov <dosantappdev@gmail.com>

* Use setTimeout to schedule monitoring steps

* settimeout

Co-authored-by: Lukas Olson <olson.lukas@gmail.com>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Anton Dosov <dosantappdev@gmail.com>

Co-authored-by: Lukas Olson <olson.lukas@gmail.com>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Anton Dosov <dosantappdev@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature:Embedding Embedding content via iFrame 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.

9 participants