retry dictionary registration - #201
Conversation
| 409: | ||
| $ref: '#/components/responses/StatusConflict' |
There was a problem hiding this comment.
if registering the same Dictionary for the category then it throws a 409 error, unless the "force" flag is true.
| - name: force | ||
| description: Re-registers the current active dictionary on the category and retries the data migration. | ||
| in: query | ||
| required: false | ||
| schema: | ||
| type: boolean | ||
| default: false |
There was a problem hiding this comment.
Can you add more detail about this behaviour? I don't know what re-registering a dictionary will do. Is this the same as initiating a migration? If the dictionary version is the same as the current dictionary will it run the migration with the intention of revalidating the data (should have no impact on the current data state)?
There was a problem hiding this comment.
description updated to Runs dictionary registration and migration again for this category, even if the same dictionary is already registered. Use this only when a previous migration ended unexpectedly and you must rerun both steps.
|
|
||
| If a category is already using the same dictionary name and version, registration returns `409 Conflict`. | ||
|
|
||
| Set the `force` query parameter to `true` to allow re-registration and trigger a migration (or retry) to revalidate existing category data against that dictionary. |
There was a problem hiding this comment.
Repeating my comment since this is the full documentation about registering dictionaries:
Can you add more detail about this behaviour? I don't know what re-registering a dictionary will do. Is this the same as initiating a migration? If the dictionary version is the same as the current dictionary will it run the migration with the intention of revalidating the data (should have no impact on the current data state)?
| const newMigration: NewDictionaryMigration = { | ||
| categoryId, | ||
| fromDictionaryId, | ||
| fromDictionaryId: fromDictionaryId ?? toDictionaryId, |
There was a problem hiding this comment.
This is confusing to read - perhaps we should leave it as required and the caller can indicate that fromDictionaryId value should be the same value as toDictionaryId. I would not expect the migration service to assume that if from value is not provided you reuse the to value.
There was a problem hiding this comment.
code updated to make fromDictionaryId required
| if (forceRegistration) { | ||
| logger.info( | ||
| LOG_MODULE, | ||
| `Force flag is true, initiating migration for Category '${foundCategory.name}' | ||
| with Dictionary '${savedDictionary.name}' version '${savedDictionary.version}'`, | ||
| ); | ||
|
|
||
| const resultMigration = await initiateMigration({ | ||
| categoryId: foundCategory.id, | ||
| toDictionaryId: savedDictionary.id, | ||
| userName: username || '', | ||
| }); | ||
|
|
||
| if (!resultMigration.success) { | ||
| const errorMessage = `Failed to initiate migration for category '${categoryName}' with error: ${resultMigration.data}`; | ||
| logger.error(LOG_MODULE, errorMessage); | ||
| throw new Error(errorMessage); | ||
| } | ||
|
|
||
| return { dictionary: savedDictionary, category: foundCategory, migrationId: resultMigration.data }; | ||
| } | ||
|
|
||
| throw new StatusConflict( | ||
| `Category '${categoryName}' with Dictionary '${savedDictionary.name}' version '${savedDictionary.version}' already exists`, | ||
| ); |
There was a problem hiding this comment.
This is not very DRY, a lot of repeated code from the else block. The only difference is omitting the fromDictionaryId and changed log statements. Is there a way to write this that won't open us up to a future code change that is only made in one branch of this if statement?
There was a problem hiding this comment.
refactored this code to make it DRY and reusing the initiateMigration logic.
|
PR updated to address feedback received. Ready for code review |
|
Could you add a bit more description to the PR to explain "what happens if the force flag is used when migration is not in failed state"? For example, does it interrupt a migration thats in progress, does it repeat a completed migration. Any behaviours that are modified by this force flag need to be claerly stated. |
|
|
||
| Category groups data that is related and shares the same data structure, for that reason, a category must be associated to a registered dictionary. Over time, if the dictionary requires an update, the category needs to be updates accordingly, See [Dictionary Migration](#dictionary-migration) for more details. | ||
|
|
||
| If a category is already using the same dictionary name and version, registration returns `409 Conflict` by default. If the `force` query parameter is set to `true`, Lyric retries only when the same dictionary is already registered and the latest migration previously failed. If no prior failed migration exists, the `force` flag is ignored. |
There was a problem hiding this comment.
updated doc to describe force flag behaviour
|
|
||
| return { dictionary: savedDictionary, category: foundCategory }; | ||
| // check last migration of this category to find if it failed, if it failed and forceRegistration is true, | ||
| // we will re-initiate the migration with the new dictionary | ||
| const activeMigration = await getMigrationsByCategoryId(foundCategory.id, { pageSize: 1, page: 1 }); | ||
|
|
||
| if ( | ||
| forceRegistration && | ||
| activeMigration.result.length === 1 && | ||
| activeMigration.result.at(0)?.status === 'FAILED' | ||
| ) { |
There was a problem hiding this comment.
a migration can be re-run only when last migration has FAILED and force flag is set to true
|
PR updated, changes on readme and openapi doc, to indicate |
* update docs * Dictionary migration - Part 1 - Database changes (#182) * database changes * update dbml * updates migration repository * update docs * migration table index * adding ts config noUncheckedIndexedAccess * rename migration enum status IN_PROGRESS * validate undefined query response * Dictionary migration - Part 2 - Execution migration (#183) * database changes * update dbml * migration services * updates migration repository * update migration service * data validation * refactor migration process * block commit submission * fix sort imports * update docs * migration table index * fix typos and logs * migration audit and logs * migration on worker thread * adding ts config noUncheckedIndexedAccess * rename migration enum status IN_PROGRESS * refactoring migration function with Result * Dictionary Migration - Get migration endpoints (#200) * database changes * update dbml * migration services * updates migration repository * update migration service * data validation * refactor migration process * block commit submission * fix sort imports * update docs * migration table index * fix typos and logs * migration audit and logs * migration on worker thread * GET migration endpoints * fix unit tests * GET migration records * adding ts config noUncheckedIndexedAccess * rename migration enum status IN_PROGRESS * refactoring migration function with Result * default constants pagination * change logs and response NotFound * fix swagger docs * include errors or migration changes * type paginated result * using type paginated result * unit test migration formatter functions * remove unhandled error thrown * return 200 json response * tsdocs updates * swagger docs update * retry dictionary registration (#201) * database changes * update dbml * migration services * updates migration repository * update migration service * data validation * refactor migration process * block commit submission * fix sort imports * update docs * migration table index * fix typos and logs * migration audit and logs * migration on worker thread * GET migration endpoints * fix unit tests * GET migration records * adding ts config noUncheckedIndexedAccess * rename migration enum status IN_PROGRESS * refactoring migration function with Result * default constants pagination * change logs and response NotFound * fix swagger docs * include errors or migration changes * type paginated result * using type paginated result * unit test migration formatter functions * remove unhandled error thrown * retry dictionary registration * updating docs * update documentation * DRY refactor * re-run migration only when. prev has failed * Dictionary Migration - Integration tests (#202) * database changes * update dbml * migration services * updates migration repository * update migration service * data validation * refactor migration process * block commit submission * fix sort imports * update docs * migration table index * fix typos and logs * migration audit and logs * migration on worker thread * GET migration endpoints * fix unit tests * GET migration records * adding ts config noUncheckedIndexedAccess * rename migration enum status IN_PROGRESS * refactoring migration function with Result * default constants pagination * change logs and response NotFound * fix swagger docs * include errors or migration changes * type paginated result * using type paginated result * unit test migration formatter functions * remove unhandled error thrown * retry dictionary registration * updating docs * fix integration tests * update documentation * DRY refactor * fix accumulate submission records test * shutdown test provider * create dictionary registration test * dictionary migration tests * tsdocs * pnpm allow build config * re-run migration only when. prev has failed * remove unused code * use common fixtures and assertion function * missing imports * unit test renaming * optional worker pool configuration * Testing workerpool configuration * change pipeline name case
* Build app using Node 22 (#205) * pnpm allow builds * update Dockerfile with node 22 * fix corepack not being found after deployment without egress * add devctx * #169: Data Dictionary Migration (#210) * update docs * Dictionary migration - Part 1 - Database changes (#182) * database changes * update dbml * updates migration repository * update docs * migration table index * adding ts config noUncheckedIndexedAccess * rename migration enum status IN_PROGRESS * validate undefined query response * Dictionary migration - Part 2 - Execution migration (#183) * database changes * update dbml * migration services * updates migration repository * update migration service * data validation * refactor migration process * block commit submission * fix sort imports * update docs * migration table index * fix typos and logs * migration audit and logs * migration on worker thread * adding ts config noUncheckedIndexedAccess * rename migration enum status IN_PROGRESS * refactoring migration function with Result * Dictionary Migration - Get migration endpoints (#200) * database changes * update dbml * migration services * updates migration repository * update migration service * data validation * refactor migration process * block commit submission * fix sort imports * update docs * migration table index * fix typos and logs * migration audit and logs * migration on worker thread * GET migration endpoints * fix unit tests * GET migration records * adding ts config noUncheckedIndexedAccess * rename migration enum status IN_PROGRESS * refactoring migration function with Result * default constants pagination * change logs and response NotFound * fix swagger docs * include errors or migration changes * type paginated result * using type paginated result * unit test migration formatter functions * remove unhandled error thrown * return 200 json response * tsdocs updates * swagger docs update * retry dictionary registration (#201) * database changes * update dbml * migration services * updates migration repository * update migration service * data validation * refactor migration process * block commit submission * fix sort imports * update docs * migration table index * fix typos and logs * migration audit and logs * migration on worker thread * GET migration endpoints * fix unit tests * GET migration records * adding ts config noUncheckedIndexedAccess * rename migration enum status IN_PROGRESS * refactoring migration function with Result * default constants pagination * change logs and response NotFound * fix swagger docs * include errors or migration changes * type paginated result * using type paginated result * unit test migration formatter functions * remove unhandled error thrown * retry dictionary registration * updating docs * update documentation * DRY refactor * re-run migration only when. prev has failed * Dictionary Migration - Integration tests (#202) * database changes * update dbml * migration services * updates migration repository * update migration service * data validation * refactor migration process * block commit submission * fix sort imports * update docs * migration table index * fix typos and logs * migration audit and logs * migration on worker thread * GET migration endpoints * fix unit tests * GET migration records * adding ts config noUncheckedIndexedAccess * rename migration enum status IN_PROGRESS * refactoring migration function with Result * default constants pagination * change logs and response NotFound * fix swagger docs * include errors or migration changes * type paginated result * using type paginated result * unit test migration formatter functions * remove unhandled error thrown * retry dictionary registration * updating docs * fix integration tests * update documentation * DRY refactor * fix accumulate submission records test * shutdown test provider * create dictionary registration test * dictionary migration tests * tsdocs * pnpm allow build config * re-run migration only when. prev has failed * remove unused code * use common fixtures and assertion function * missing imports * unit test renaming * optional worker pool configuration * Testing workerpool configuration * change pipeline name case * publish committed records to Kafka document topic (#208) * bump version * fix: surface file parse errors with fault isolation and structured logging (#212) Each file in a batch submission is now processed independently: a stream error or schema validation failure on one file is caught and reported without blocking the remaining files. Parse results use a three-state discriminator (ok/invalid/error) and are returned synchronously in the API response, so callers know immediately which files failed and why. Structured logging separates human-readable console output (key=value) from a JSON file transport (LOG_JSON env var) for log aggregator ingestion. Field names and line numbers are logged for schema errors; field values are not (OWASP A03). Bonus: Adds optional sync=false query parameter to the file upload endpoint to allow background parsing for very large batches; when omitted or true, behaviour is synchronous and unchanged from the existing default. - New submissionUtils.spec.ts: 5 tests for submissionInsertDataFromFiles covering ok/invalid/error paths, fault isolation, and multi-file accumulation - Extended schemas.spec.ts with 4 tests for the sync query parameter - Fixed collectRows: source ReadStream errors (ENOENT) were not caught when only the piped csvParse transform had an error listener; both streams now handle errors to prevent uncaught rejections - Updated .mocharc.json to discover co-located src/**/*.spec.ts files (following modules/barrels simplifies relocation later if needed) - Updated tech-debt entry for test placement with concrete migration details --------- Co-authored-by: Anders Richardsson <2107110+justincorrigible@users.noreply.github.com>
* Build app using Node 22 (#205) * pnpm allow builds * update Dockerfile with node 22 * fix corepack not being found after deployment without egress * add devctx * #169: Data Dictionary Migration (#210) * update docs * Dictionary migration - Part 1 - Database changes (#182) * database changes * update dbml * updates migration repository * update docs * migration table index * adding ts config noUncheckedIndexedAccess * rename migration enum status IN_PROGRESS * validate undefined query response * Dictionary migration - Part 2 - Execution migration (#183) * database changes * update dbml * migration services * updates migration repository * update migration service * data validation * refactor migration process * block commit submission * fix sort imports * update docs * migration table index * fix typos and logs * migration audit and logs * migration on worker thread * adding ts config noUncheckedIndexedAccess * rename migration enum status IN_PROGRESS * refactoring migration function with Result * Dictionary Migration - Get migration endpoints (#200) * database changes * update dbml * migration services * updates migration repository * update migration service * data validation * refactor migration process * block commit submission * fix sort imports * update docs * migration table index * fix typos and logs * migration audit and logs * migration on worker thread * GET migration endpoints * fix unit tests * GET migration records * adding ts config noUncheckedIndexedAccess * rename migration enum status IN_PROGRESS * refactoring migration function with Result * default constants pagination * change logs and response NotFound * fix swagger docs * include errors or migration changes * type paginated result * using type paginated result * unit test migration formatter functions * remove unhandled error thrown * return 200 json response * tsdocs updates * swagger docs update * retry dictionary registration (#201) * database changes * update dbml * migration services * updates migration repository * update migration service * data validation * refactor migration process * block commit submission * fix sort imports * update docs * migration table index * fix typos and logs * migration audit and logs * migration on worker thread * GET migration endpoints * fix unit tests * GET migration records * adding ts config noUncheckedIndexedAccess * rename migration enum status IN_PROGRESS * refactoring migration function with Result * default constants pagination * change logs and response NotFound * fix swagger docs * include errors or migration changes * type paginated result * using type paginated result * unit test migration formatter functions * remove unhandled error thrown * retry dictionary registration * updating docs * update documentation * DRY refactor * re-run migration only when. prev has failed * Dictionary Migration - Integration tests (#202) * database changes * update dbml * migration services * updates migration repository * update migration service * data validation * refactor migration process * block commit submission * fix sort imports * update docs * migration table index * fix typos and logs * migration audit and logs * migration on worker thread * GET migration endpoints * fix unit tests * GET migration records * adding ts config noUncheckedIndexedAccess * rename migration enum status IN_PROGRESS * refactoring migration function with Result * default constants pagination * change logs and response NotFound * fix swagger docs * include errors or migration changes * type paginated result * using type paginated result * unit test migration formatter functions * remove unhandled error thrown * retry dictionary registration * updating docs * fix integration tests * update documentation * DRY refactor * fix accumulate submission records test * shutdown test provider * create dictionary registration test * dictionary migration tests * tsdocs * pnpm allow build config * re-run migration only when. prev has failed * remove unused code * use common fixtures and assertion function * missing imports * unit test renaming * optional worker pool configuration * Testing workerpool configuration * change pipeline name case * publish committed records to Kafka document topic (#208) * fix: surface file parse errors with fault isolation and structured logging (#212) Each file in a batch submission is now processed independently: a stream error or schema validation failure on one file is caught and reported without blocking the remaining files. Parse results use a three-state discriminator (ok/invalid/error) and are returned synchronously in the API response, so callers know immediately which files failed and why. Structured logging separates human-readable console output (key=value) from a JSON file transport (LOG_JSON env var) for log aggregator ingestion. Field names and line numbers are logged for schema errors; field values are not (OWASP A03). Bonus: Adds optional sync=false query parameter to the file upload endpoint to allow background parsing for very large batches; when omitted or true, behaviour is synchronous and unchanged from the existing default. - New submissionUtils.spec.ts: 5 tests for submissionInsertDataFromFiles covering ok/invalid/error paths, fault isolation, and multi-file accumulation - Extended schemas.spec.ts with 4 tests for the sync query parameter - Fixed collectRows: source ReadStream errors (ENOENT) were not caught when only the piped csvParse transform had an error listener; both streams now handle errors to prevent uncaught rejections - Updated .mocharc.json to discover co-located src/**/*.spec.ts files (following modules/barrels simplifies relocation later if needed) - Updated tech-debt entry for test placement with concrete migration details * docs: log a roadmap item for fixing invalid submissions in place An effort-estimate pass for a submitter complaint found the state machine, re-validation trigger, and delete-by-index scaffolding already support this; the actual gap is that resubmission appends rather than replaces an entity's batch. Logged for a future agent to pick up. * feat: category alias, plus routing Kafka messages by categoryId when a topic is shared (#213) Adds category alias as a first-class feature: assignable at creation, resolvable via GET, and assignable/unassignable after the fact for categories created before this feature existed. Publishes categoryId/categoryAlias on every committed Kafka message, so a consumer sharing one topic across multiple categories, like Maestro, can route correctly, the wrong-index bug this whole thing started from. Review-driven correctness fixes folded in: - Numeric category id always wins over a colliding alias on lookup, ids are permanent, aliases can be assigned/cleared/reassigned - An alias can never be purely numeric, eliminating that collision at the source rather than only handling it gracefully after the fact - categoryId-or-alias resolution now applied consistently across every controller that accepts a categoryId path param (dictionary, submission, audit, migration, submittedData, validator routes); a nonexistent category id or alias now consistently returns 404 everywhere instead of a mix of 400 and 404 * bump version 0.19.0 --------- Co-authored-by: Anders Richardsson <2107110+justincorrigible@users.noreply.github.com>
Description
It enables the possibility to retry "failed" Dictionary migration by adding a
forceflag on the Dictionary Registration endpoint.Details:
POST /dictionary/registerendpoint to accept an optional query paramforceto Re-register the current active dictionary on the category and retries the data migration.Related tickets:
This PR depends on: