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

Alternative approach: Let the model sort out the logic #49

Conversation

TinaHeiligers
Copy link
Owner

@TinaHeiligers TinaHeiligers commented Apr 10, 2021

Summary

This explores an alternative approach to handling saved objects that can't be transformed.
The approach assumes we have PIT search and won't attempt to transform documents that have already failed transformation.
This approach does the following:

  • migrate_run_docs uses a new method, migrateRawDocsNonThrowing that returns both the processed docs and the ids of those that couldn't be processed as arrays.
    • The new failedDocsIds contains the ids of those documents that we previously threw a CorruptSavedObjectError for.
    • The whole process flow for running migrations scripts is now wrapped in a try-catch, to catch any serious errors such as a migration script throwing an error.
  • The migrationV2 model now does the following after OUTDATED_DOCUMENTS_SEARCH handls control flow to OUTDATED_DOCUMENTS_TRANSFORM:
    • If we have outdated documents passed in, we try to transform them
    • The response contains two arrays: { processedDocs: SavedObjectRawDoc[], failedDocs: string[] }
    • We now handle four cases based on what the result is:
      • If we don't have any failed docs and we haven't seen any failed docs yet (there aren't any on state), then we hand control flow off to TRANSFORMED_DOCUMENTS_BULK_INDEX.
        • TRANSFORMED_DOCUMENTS_BULK_INDEX bulk indexes the transformed documents and passes control flow back to OUTDATED_DOCUMENTS_SEARCH to carry on searching.
      • If we don't have any new failed docs but we've already encountered failed docs (collected on state previously), then we carry on searching.
      • If we have new failed docs from the transform but still haven't seen any other yet, then we add these failed document ids to a new state variable: failedDocumentIds: string[] and pass the control flow back to OUTDATED_DOCUMENTS_SEARCH. Note: We explicitly don't carry on indexing the transformed documents because we already know the migration will ultimately fail.
      • If we have new failed docs and we've already encountered failed docs (collected on state previously), then we add the newly failed docs to those on state (avoiding mutating state), and carry on searching.
    • Eventually, OUTDATED_DOCUMENTS_SEARCH will throw a CorruptSavedObject Error (that triggers dumping the logs) when it sees there aren't any more outdated documents to search and we have failed documents on state. If there aren't any failed documents on state and we've searched through all the outdated docs, we continue along the happy migration path.

All types were updated (I think) but no tests have been refactored yet. There's also an issue now that the model complains to not have a final return statement and that undefined is not declared on State.

PROBLEM: I'm not sure where the issue with the model not having a final return statement is coming from. Is it because we're not dealing with a Task?

…nother for SO docs that can't be processed, adapts control flow through the model of how to handle the new return type, splits bulk indexing of transformed documents out from next, resumes searching for outdated docs after the bulk index is done
…uptSavedObject error in OUTDATED_DOCUMENTS_SEARCH if we have failed docs and no new outdated documents. Current issue: The model now claims to not have a final return and that undefined is not on the State type
@TinaHeiligers TinaHeiligers changed the title Initial notes Alternative approach: Let the model sort out the logic Apr 11, 2021
// documents and can proceed to the next step
if (stateP.failedDocumentIds && stateP.failedDocumentIds?.length > 0) {
// we exit out here and throw an error with the ids of documents that we'ren't transformed
throw new CorruptSavedObjectError(stateP.failedDocumentIds?.toString());
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: I've been trying to avoid using exceptions for control flow. So basically we only throw an exception if something unexpected happens that we have no idea how to handle. If there's a known failure condition we go to the FATAL state. E.g. when there's a newer Kibana we want to fail, but this is a condition we fully expect to happen so we handle it explicitly https://github.com/elastic/kibana/blob/master/src/core/server/saved_objects/migrationsv2/model.ts#L715-L716

Copy link
Owner Author

Choose a reason for hiding this comment

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

Ok, that makes sense, especially because we're handling the failed docs as a right. Should we then rather handle this as a failure condition? We want migrations to stop after we've built up the full list of failed docs. Should we rather try the approach of creating a TaskEither from the async transform method?

Copy link
Collaborator

@rudolf rudolf Apr 12, 2021

Choose a reason for hiding this comment

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

Instead of throwing we would just go to the FATAL state with a reason string. The code changed after I posted, so the link is no longer showing the correct lines.

But I meant something like:

        return {
          ...stateP,
          controlState: 'FATAL',
          reason: '... migrations failed because of the following corrupt saved object documents: [...]',
        };

Copy link
Owner Author

@TinaHeiligers TinaHeiligers Apr 12, 2021

Choose a reason for hiding this comment

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

I thought about that too but then realized we're specifically targeting CorruptSavedObjectError within the catch block of migrationStateActionMachine, where we throw a new Error with a custom message. I guess we won't need to target CorruptSavedObjectError anymore if we're going to the FATAL state with a detailed reason.

@@ -191,12 +191,25 @@ export type UpdateTargetMappingsWaitForTaskState = PostInitState & {
export type OutdatedDocumentsSearch = PostInitState & {
/** Search for outdated documents in the target index */
readonly controlState: 'OUTDATED_DOCUMENTS_SEARCH';
readonly failedDocumentIds?: string[];
Copy link
Collaborator

Choose a reason for hiding this comment

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

might be simpler to not make this property optional otherwise we have three states:

  1. undefined
  2. empty array (no failures)
  3. non-empty array (some failures)

But we don't need or use (1), so we can rather initialize an empty array and then we don't need to use failedDocumentIds! in other places.

@TinaHeiligers
Copy link
Owner Author

abandoned approach in favor of elastic#96986

@TinaHeiligers TinaHeiligers deleted the so-migrations/collect-failing-docs-report-both-as-right branch April 20, 2021 17:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants