-
Notifications
You must be signed in to change notification settings - Fork 5
Feature/ccm 12934 create letter queue #410
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
Merged
Merged
Changes from 4 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
fafbd99
CCM-12934 Add LetterQueue table
stevebux 687c038
Merge remote-tracking branch 'origin/main' into feature/CCM-12934-Cre…
stevebux eaebcc6
Fix metrics
stevebux b20e2e1
Switch table indexes around
stevebux 46e6406
Fix resource name for lambda
stevebux 9b70187
Fix resource name
stevebux efc0c72
More terraform fixes
stevebux af08d3c
Fix return value in case of error
stevebux ecbcc60
Fix LSI name
stevebux 5a2a2d4
Merge remote-tracking branch 'origin/main' into feature/CCM-12934-Cre…
stevebux File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 44 additions & 0 deletions
44
infrastructure/terraform/components/api/ddb_table_letter_queue.tf
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| resource "aws_dynamodb_table" "letter-queue" { | ||
| name = "${local.csi}-letter-queue" | ||
| billing_mode = "PAY_PER_REQUEST" | ||
|
|
||
| hash_key = "supplierId" | ||
| range_key = "queueTimestamp" | ||
|
|
||
| ttl { | ||
| attribute_name = "ttl" | ||
| enabled = true | ||
| } | ||
|
|
||
| local_secondary_index { | ||
| name = "timestamp-index" | ||
| range_key = "letterId" | ||
| projection_type = "ALL" | ||
| } | ||
|
|
||
| attribute { | ||
| name = "supplierId" | ||
| type = "S" | ||
| } | ||
|
|
||
| attribute { | ||
| name = "letterId" | ||
| type = "S" | ||
| } | ||
|
|
||
| attribute { | ||
| name = "queueTimestamp" | ||
| type = "S" | ||
| } | ||
|
|
||
| point_in_time_recovery { | ||
| enabled = true | ||
| } | ||
|
|
||
| tags = merge( | ||
| local.default_tags, | ||
| { | ||
| NHSE-Enable-Dynamo-Backup-Acct = "True" | ||
| } | ||
| ) | ||
| } | ||
11 changes: 11 additions & 0 deletions
11
infrastructure/terraform/components/api/event_source_mapping_update_letter_queue.tf
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| resource "aws_lambda_event_source_mapping" "update_letter_queue_kinesis" { | ||
| event_source_arn = aws_kinesis_stream.letter_change_stream.arn | ||
| function_name = module.update_letter_queue.function_arn | ||
| starting_position = "LATEST" | ||
| batch_size = 10 | ||
| maximum_batching_window_in_seconds = 1 | ||
|
|
||
| depends_on = [ | ||
| module.update_letter_queue # ensures update letter queue lambda exists | ||
| ] | ||
| } |
75 changes: 75 additions & 0 deletions
75
infrastructure/terraform/components/api/module_lambda_update_letter_queue.tf
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| module "update_letter_queue" { | ||
| source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.29/terraform-lambda.zip" | ||
|
|
||
| function_name = "update-letter-queue" | ||
| description = "Populates the letter queue table with new pending letters from the letter change stream" | ||
|
|
||
| aws_account_id = var.aws_account_id | ||
| component = var.component | ||
| environment = var.environment | ||
| project = var.project | ||
| region = var.region | ||
| group = var.group | ||
|
|
||
| log_retention_in_days = var.log_retention_in_days | ||
| kms_key_arn = module.kms.key_arn | ||
|
|
||
| iam_policy_document = { | ||
| body = data.aws_iam_policy_document.update_letter_queue_lambda.json | ||
| } | ||
|
|
||
| function_s3_bucket = local.acct.s3_buckets["lambda_function_artefacts"]["id"] | ||
| function_code_base_path = local.aws_lambda_functions_dir_path | ||
| function_code_dir = "update-letter-queue/dist" | ||
| function_include_common = true | ||
| handler_function_name = "handler" | ||
| runtime = "nodejs22.x" | ||
| memory = 512 | ||
| timeout = 29 | ||
| log_level = var.log_level | ||
|
|
||
| force_lambda_code_deploy = var.force_lambda_code_deploy | ||
| enable_lambda_insights = false | ||
|
|
||
| log_destination_arn = local.destination_arn | ||
| log_subscription_role_arn = local.acct.log_subscription_role_arn | ||
|
|
||
| lambda_env_vars = merge(local.common_lambda_env_vars, { | ||
| LETTER_QUEUE_TABLE_NAME = aws_dynamodb_table.letter-queue.name, | ||
| LETTER_QUEUE_TTL_HOURS = 168 # 7 days | ||
| }) | ||
| } | ||
|
|
||
| data "aws_iam_policy_document" "update_letter_queue_lambda" { | ||
| statement { | ||
| sid = "AllowDynamoDBWrite" | ||
| effect = "Allow" | ||
|
|
||
| actions = [ | ||
| "dynamodb:PutItem", | ||
| ] | ||
|
|
||
| resources = [ | ||
| aws_dynamodb_table.letter-queue.arn, | ||
| "${aws_dynamodb_table.letter-queue.arn}/index/*" | ||
| ] | ||
| } | ||
|
|
||
| statement { | ||
| sid = "AllowKinesisGet" | ||
| effect = "Allow" | ||
|
|
||
| actions = [ | ||
| "kinesis:GetRecords", | ||
| "kinesis:GetShardIterator", | ||
| "kinesis:DescribeStream", | ||
| "kinesis:DescribeStreamSummary", | ||
| "kinesis:ListShards", | ||
| "kinesis:ListStreams", | ||
| ] | ||
|
|
||
| resources = [ | ||
| aws_kinesis_stream.letter_change_stream.arn | ||
| ] | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
104 changes: 104 additions & 0 deletions
104
internal/datastore/src/__test__/letter-queue-repository.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| import { Logger } from "pino"; | ||
| import { | ||
| DBContext, | ||
| createTables, | ||
| deleteTables, | ||
| setupDynamoDBContainer, | ||
| } from "./db"; | ||
| import LetterQueueRepository from "../letter-queue-repository"; | ||
| import { InsertPendingLetter } from "../types"; | ||
| import { LetterAlreadyExistsError } from "../errors"; | ||
| import { createTestLogger } from "./logs"; | ||
|
|
||
| function createLetter(letterId = "letter1"): InsertPendingLetter { | ||
| return { | ||
| letterId, | ||
| supplierId: "supplier1", | ||
| specificationId: "specification1", | ||
| groupId: "group1", | ||
| }; | ||
| } | ||
|
|
||
| // Database tests can take longer, especially with setup and teardown | ||
| jest.setTimeout(30_000); | ||
|
|
||
| describe("LetterQueueRepository", () => { | ||
| let db: DBContext; | ||
| let letterQueueRepository: LetterQueueRepository; | ||
| let logger: Logger; | ||
|
|
||
| beforeAll(async () => { | ||
| db = await setupDynamoDBContainer(); | ||
| }); | ||
|
|
||
| beforeEach(async () => { | ||
| await createTables(db); | ||
| ({ logger } = createTestLogger()); | ||
|
|
||
| letterQueueRepository = new LetterQueueRepository( | ||
| db.docClient, | ||
| logger, | ||
| db.config, | ||
| ); | ||
| }); | ||
|
|
||
| afterEach(async () => { | ||
| await deleteTables(db); | ||
| jest.useRealTimers(); | ||
| }); | ||
|
|
||
| afterAll(async () => { | ||
| await db.container.stop(); | ||
| }); | ||
|
|
||
| function assertTtl(ttl: number, before: number, after: number) { | ||
| const expectedLower = Math.floor( | ||
| before / 1000 + 60 * 60 * db.config.letterQueueTtlHours, | ||
| ); | ||
| const expectedUpper = Math.floor( | ||
| after / 1000 + 60 * 60 * db.config.lettersTtlHours, | ||
| ); | ||
| expect(ttl).toBeGreaterThanOrEqual(expectedLower); | ||
| expect(ttl).toBeLessThanOrEqual(expectedUpper); | ||
| } | ||
|
|
||
| describe("putLetter", () => { | ||
| it("adds a letter to the database", async () => { | ||
| const before = Date.now(); | ||
|
|
||
| const pendingLetter = | ||
| await letterQueueRepository.putLetter(createLetter()); | ||
|
|
||
| const after = Date.now(); | ||
|
|
||
| const timestampInMillis = new Date( | ||
| pendingLetter.queueTimestamp, | ||
| ).valueOf(); | ||
| expect(timestampInMillis).toBeGreaterThanOrEqual(before); | ||
| expect(timestampInMillis).toBeLessThanOrEqual(after); | ||
| assertTtl(pendingLetter.ttl, before, after); | ||
| }); | ||
|
|
||
| it("throws LetterAlreadyExistsError when creating a letter which already exists", async () => { | ||
| await letterQueueRepository.putLetter(createLetter()); | ||
|
|
||
| await expect( | ||
| letterQueueRepository.putLetter(createLetter()), | ||
| ).rejects.toThrow(LetterAlreadyExistsError); | ||
| }); | ||
|
|
||
| it("rethrows errors from DynamoDB when creating a letter", async () => { | ||
| const misconfiguredRepository = new LetterQueueRepository( | ||
| db.docClient, | ||
| logger, | ||
| { | ||
| ...db.config, | ||
| letterQueueTableName: "nonexistent-table", | ||
| }, | ||
| ); | ||
| await expect( | ||
| misconfiguredRepository.putLetter(createLetter()), | ||
| ).rejects.toThrow("Cannot do operations on a non-existent table"); | ||
| }); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| /** | ||
| * Error thrown when attempting to create a letter that already exists in the database. | ||
| */ | ||
| // eslint-disable-next-line import-x/prefer-default-export | ||
| export class LetterAlreadyExistsError extends Error { | ||
| constructor( | ||
| public readonly supplierId: string, | ||
| public readonly letterId: string, | ||
| ) { | ||
| super( | ||
| `Letter already exists: supplierId=${supplierId}, letterId=${letterId}`, | ||
| ); | ||
| this.name = "LetterAlreadyExistsError"; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,7 @@ | ||
| export * from "./types"; | ||
| export * from "./errors"; | ||
| export * from "./mi-repository"; | ||
| export * from "./letter-repository"; | ||
| export * from "./supplier-repository"; | ||
| export { default as LetterQueueRepository } from "./letter-queue-repository"; | ||
| export { default as DBHealthcheck } from "./healthcheck"; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.