Skip to content

CCM-13304: Generate reports#203

Open
simonlabarere wants to merge 31 commits intomainfrom
feature/CCM-13304_generate_reports
Open

CCM-13304: Generate reports#203
simonlabarere wants to merge 31 commits intomainfrom
feature/CCM-13304_generate_reports

Conversation

@simonlabarere
Copy link
Contributor

@simonlabarere simonlabarere commented Feb 10, 2026

Description

Generate report component.
image

Testing

Generate Report Event
image

Report Generated in S3
image

Report Generated Event
image

Type of changes

  • Refactoring (non-breaking change)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would change existing functionality)
  • Bug fix (non-breaking change which fixes an issue)

Checklist

  • I am familiar with the contributing guidelines
  • I have followed the code style of the project
  • I have added tests to cover my changes
  • I have updated the documentation accordingly
  • This PR is a result of pair or mob programming
  • If I have used the 'skip-trivy-package' label I have done so responsibly and in the knowledge that this is being fixed as part of a separate ticket/PR.

Sensitive Information Declaration

To ensure the utmost confidentiality and protect your and others privacy, we kindly ask you to NOT including PII (Personal Identifiable Information) / PID (Personal Identifiable Data) or any other sensitive data in this PR (Pull Request) and the codebase changes. We will remove any PR that do contain any sensitive information. We really appreciate your cooperation in this matter.

  • I confirm that neither PII/PID nor sensitive data are included in this PR and the codebase changes.

@simonlabarere simonlabarere requested review from a team as code owners February 10, 2026 10:21
apim_api_key_ssm_parameter_name = "/${var.component}/${var.environment}/apim/api_key"
apim_keystore_s3_bucket = "nhs-${var.aws_account_id}-${var.region}-${var.environment}-${var.component}-static-assets"
apim_private_key_ssm_parameter_name = "/${var.component}/${var.environment}/apim/private_key"
athena_reporting_database = "${local.csi}-reporting"
Copy link
Contributor

Choose a reason for hiding this comment

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

I think instead of this local we should just reference the name of the DB from glue_catalog_database_reporting.tf file. E.g. use aws_glue_catalog_database.reporting.name instead of local.athena_reporting_database.

variable "athena_query_max_polling_attemps" {
type = number
description = "The number of times athena will be polled to check if a query is completed"
default = 50
Copy link
Contributor

Choose a reason for hiding this comment

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

Is 50 attempts not a bit high?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I copied this from core.

Comment on lines +8 to +12
export type DataRepositoryDependencies = {
athenaClient: AthenaClient;
config: Record<string, string>;
logger: Logger;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

This type doesn't appear to be used.

Also, I think we'd be better making config an object with specific named properties, rather than a generic record. Then we can rely on the compiler to ensure the correct arguments have been passed.

Comment on lines +17 to +39
export const createStorageRepository = ({
logger,
reportingBucketName,
s3Client,
}: StorageRepositoryDependencies): IStorageRepository => ({
async publishReport(reportQueryId: string, reportFilePath: string) {
logger.debug(
`Publishing report data to ${reportFilePath} for query ${reportQueryId}`,
);

const copyObjectCommand = new CopyObjectCommand({
CopySource: `${reportingBucketName}/athena-output/${reportQueryId}.csv`,
Bucket: reportingBucketName,
Key: reportFilePath,
});

await s3Client.send(copyObjectCommand);

logger.info(`Report stored at ${reportingBucketName}/${reportFilePath}.`);

return `s3://${reportingBucketName}/${reportFilePath}`;
},
});
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this could be a class, for consistency with the report service and data repository, rather than a function that returns a function.

Comment on lines +75 to +96
private async poll(
queryId: string,
maxPollLimit: number,
waitForInSeconds: number,
) {
let count = 0;
let status = 'QUEUED';

while (
count < maxPollLimit &&
['QUEUED', 'RUNNING', 'UNKNOWN'].includes(status)
) {
status = (await this.dataRepository.getQueryStatus(queryId)) || 'UNKNOWN';

count += 1;

await sleep(waitForInSeconds);
}

return status;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we not use util-retry for this, rather than implementing our own logic here?

Comment on lines +160 to +173
if (submittedFailedEvents.length > 0) {
logger.warn({
description: 'Some successful events failed to publish',
failedCount: submittedFailedEvents.length,
totalAttempted: successfulItems.length,
});
}
} catch (error) {
logger.warn({
err: error,
description: 'Failed to send successful events to EventBridge',
eventCount: successfulItems.length,
});
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we be DLQing the message (directly, so we don't retry it) if the event publish fails? I know we're not actually doing anything with the event that's published at the moment, but I think that's the pattern we've used elsewhere, and I think as a general rule the component publishing the event shouldn't necessarily be aware of what's consuming it (so we should treat this as if an event in use has failed). I think adding the incoming event to a DLQ allows us to examine it and determine whether we need to trigger something else downstream, etc.

@gareth-allan gareth-allan requested a review from a team as a code owner February 13, 2026 13:54
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