-
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
[Search] Session SO polling #84225
[Search] Session SO polling #84225
Conversation
@elasticmachine merge upstream |
merge conflict between base and head |
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.
Code review only: Spaces changes (unit test mocks) LGTM!
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.
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
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 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 |
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 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'], |
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.
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
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.
Created an issue for this #85252
x-pack/plugins/data_enhanced/server/search/session/session_service.ts
Outdated
Show resolved
Hide resolved
}; | ||
|
||
public asScopedProvider = ({ savedObjects }: CoreStart) => { | ||
return (request: KibanaRequest) => { |
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.
👍 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.
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.
So how should this be correctly addressed?
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.
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 |
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.
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 |
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.
Not sure what your timeline looks like, but we are starting work on OLS Phase 1, which might prove useful here.
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.
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.
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()); |
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 your thinking just that we might as well only do the updating in the monitoring task rather than here as well?
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.
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)
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.
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()); |
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.
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'; |
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.
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.
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.
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?
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.
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
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'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 🤷
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.
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?
x-pack/plugins/data_enhanced/server/search/session/session_service.ts
Outdated
Show resolved
Hide resolved
import { createRequestHash } from './utils'; | ||
import moment from 'moment'; |
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.
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
x-pack/plugins/data_enhanced/server/search/session/session_service.ts
Outdated
Show resolved
Hide resolved
x-pack/plugins/data_enhanced/server/search/session/session_service.ts
Outdated
Show resolved
Hide resolved
x-pack/plugins/data_enhanced/server/search/session/session_service.ts
Outdated
Show resolved
Hide resolved
// 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()); |
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.
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.
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 we add retry mechanism for this snippet in case we retrieved a session but there is yet no searches with that hash?
kibana/x-pack/plugins/data_enhanced/server/search/session/session_service.ts
Lines 336 to 340 in e85da48
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 <[email protected]>
return sessionSavedObject; | ||
}); | ||
|
||
const updateResults = await this.internalSavedObjectsClient.bulkUpdate<BackgroundSessionSavedObjectAttributes>( |
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 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)
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.
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.
…vice.ts Co-authored-by: Anton Dosov <[email protected]>
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, didn't test.
re-reviewed interval
-> timeout
change
💚 Build SucceededMetrics [docs]Saved Objects .kibana field count
History
To update your PR or re-run it, just comment with: |
* 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 <[email protected]> * Update x-pack/plugins/data_enhanced/server/search/session/session_service.ts Co-authored-by: Anton Dosov <[email protected]> * Use setTimeout to schedule monitoring steps * settimeout Co-authored-by: Lukas Olson <[email protected]> Co-authored-by: Kibana Machine <[email protected]> Co-authored-by: Anton Dosov <[email protected]>
…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
* 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 <[email protected]> * Update x-pack/plugins/data_enhanced/server/search/session/session_service.ts Co-authored-by: Anton Dosov <[email protected]> * Use setTimeout to schedule monitoring steps * settimeout Co-authored-by: Lukas Olson <[email protected]> Co-authored-by: Kibana Machine <[email protected]> Co-authored-by: Anton Dosov <[email protected]> Co-authored-by: Lukas Olson <[email protected]> Co-authored-by: Kibana Machine <[email protected]> Co-authored-by: Anton Dosov <[email protected]>
Summary
Blocked by #84837This 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