-
Notifications
You must be signed in to change notification settings - Fork 0
retry dictionary registration #201
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
base: feat/dictionary_migration
Are you sure you want to change the base?
Changes from all commits
74d088a
28f683a
e1ada63
c1f87dd
118fc42
0a26540
1ec4dc4
afc4f87
58d4ad8
b081dd9
e6dc14d
608c096
b23d648
8688240
2487bbe
96b6c63
d351b2e
fb05263
b5d6756
f5af236
d7d17d0
2d05348
2758202
b8cd961
cdf32cc
2c889d1
430ea27
c512349
f5994eb
280395f
c682a47
b41d1ad
6f231ce
4f7a01b
57cf05b
8f69160
a1c4d8f
e588d0b
d8b930d
a7cfcf1
a2b05e8
f28c9aa
feb65f5
ec4a580
7bc39c6
3871c59
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,9 +2,17 @@ | |
|
|
||
| /dictionary/register: | ||
| post: | ||
| summary: Register new dictionary | ||
| summary: Register a dictionary to a category. Creates the category if it does not exist, or updates its active dictionary and triggers a data migration to validate and update existing data against the new dictionary. | ||
| tags: | ||
| - Dictionary | ||
| parameters: | ||
| - name: force | ||
| description: Retries migration for this category only when the same dictionary is already registered and the most recent migration previously failed. If there is no previous failed migration, this flag is ignored. | ||
| in: query | ||
| required: false | ||
| schema: | ||
| type: boolean | ||
| default: false | ||
| requestBody: | ||
| content: | ||
| application/json: | ||
|
|
@@ -38,8 +46,8 @@ | |
| $ref: '#/components/responses/BadRequest' | ||
| 401: | ||
| $ref: '#/components/responses/UnauthorizedError' | ||
| 404: | ||
| $ref: '#/components/responses/NotFound' | ||
| 409: | ||
| $ref: '#/components/responses/StatusConflict' | ||
|
Comment on lines
+49
to
+50
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if registering the same Dictionary for the category then it throws a |
||
| 500: | ||
| $ref: '#/components/responses/ServerError' | ||
| 503: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -108,6 +108,8 @@ A Category is uniquely identified by its case-sensitive `categoryName`. | |
|
|
||
| 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. | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updated doc to describe |
||
|
|
||
| ## Centric entity | ||
|
|
||
| Some dictionaries define a centric entity, representing the root of the data model hierarchy (used on compound views). | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,7 +7,7 @@ import { BaseDependencies } from '../config/config.js'; | |
| import lecternClient from '../external/lecternClient.js'; | ||
| import categoryRepository from '../repository/categoryRepository.js'; | ||
| import dictionaryRepository from '../repository/dictionaryRepository.js'; | ||
| import { BadRequest } from '../utils/errors.js'; | ||
| import { BadRequest, StatusConflict } from '../utils/errors.js'; | ||
| import migrationService from './migrationService.js'; | ||
|
|
||
| const dictionaryService = (dependencies: BaseDependencies) => { | ||
|
|
@@ -99,20 +99,22 @@ const dictionaryService = (dependencies: BaseDependencies) => { | |
| dictionaryVersion, | ||
| defaultCentricEntity, | ||
| username, | ||
| forceRegistration = false, | ||
| }: { | ||
| categoryName: string; | ||
| dictionaryName: string; | ||
| dictionaryVersion: string; | ||
| defaultCentricEntity?: string; | ||
| username?: string; | ||
| forceRegistration?: boolean; | ||
| }): Promise<{ dictionary: Dictionary; category: Category; migrationId?: number }> => { | ||
| logger.debug( | ||
| LOG_MODULE, | ||
| `Register new dictionary categoryName '${categoryName}' dictionaryName '${dictionaryName}' dictionaryVersion '${dictionaryVersion}'`, | ||
| ); | ||
|
|
||
| const categoryRepo = categoryRepository(dependencies); | ||
| const { initiateMigration } = migrationService(dependencies); | ||
| const { initiateMigration, getMigrationsByCategoryId } = migrationService(dependencies); | ||
|
|
||
| const dictionary = await fetchDictionaryByVersion(dictionaryName, dictionaryVersion); | ||
|
|
||
|
|
@@ -131,11 +133,62 @@ const dictionaryService = (dependencies: BaseDependencies) => { | |
| // Check if Category exist | ||
| const foundCategory = await categoryRepo.getCategoryByName(categoryName); | ||
|
|
||
| const initiateMigrationOrThrow = async ({ | ||
| categoryId, | ||
| fromDictionaryId, | ||
| toDictionaryId, | ||
| }: { | ||
| categoryId: number; | ||
| fromDictionaryId: number; | ||
| toDictionaryId: number; | ||
| }): Promise<number> => { | ||
| const resultMigration = await initiateMigration({ | ||
| categoryId, | ||
| fromDictionaryId, | ||
| toDictionaryId, | ||
| 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 resultMigration.data; | ||
| }; | ||
|
|
||
| if (foundCategory && foundCategory.activeDictionaryId === savedDictionary.id) { | ||
| // Dictionary and Category already exists | ||
| logger.info(LOG_MODULE, `Dictionary and Category already exists`); | ||
|
|
||
| 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' | ||
| ) { | ||
|
Comment on lines
164
to
+173
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. a migration can be re-run only when last migration has |
||
| logger.info( | ||
| LOG_MODULE, | ||
| `Force flag is true, initiating migration for Category '${foundCategory.name}' | ||
| with Dictionary '${savedDictionary.name}' version '${savedDictionary.version}'`, | ||
| ); | ||
|
|
||
| const migrationId = await initiateMigrationOrThrow({ | ||
| categoryId: foundCategory.id, | ||
| fromDictionaryId: foundCategory.activeDictionaryId, | ||
| toDictionaryId: savedDictionary.id, | ||
| }); | ||
|
|
||
| return { dictionary: savedDictionary, category: foundCategory, migrationId }; | ||
| } | ||
|
|
||
| throw new StatusConflict( | ||
| `Category '${categoryName}' with Dictionary '${savedDictionary.name}' version '${savedDictionary.version}' already exists`, | ||
| ); | ||
| } else if (foundCategory && foundCategory.activeDictionaryId !== savedDictionary.id) { | ||
| // Update the dictionary on existing Category | ||
| const updatedCategory = await categoryRepo.update(foundCategory.id, { | ||
|
|
@@ -144,25 +197,18 @@ const dictionaryService = (dependencies: BaseDependencies) => { | |
| updatedBy: username, | ||
| }); | ||
|
|
||
| const resultMigration = await initiateMigration({ | ||
| const migrationId = await initiateMigrationOrThrow({ | ||
| categoryId: updatedCategory.id, | ||
| fromDictionaryId: foundCategory.activeDictionaryId, | ||
| 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); | ||
| } | ||
|
|
||
| logger.info( | ||
| LOG_MODULE, | ||
| `Category '${updatedCategory.name}' updated successfully with Dictionary '${savedDictionary.name}' version '${savedDictionary.version}'`, | ||
| ); | ||
|
|
||
| return { dictionary: savedDictionary, category: updatedCategory, migrationId: resultMigration.data }; | ||
| return { dictionary: savedDictionary, category: updatedCategory, migrationId }; | ||
| } else { | ||
| // Create a new Category | ||
| const newCategory: NewCategory = { | ||
|
|
||
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.