diff --git a/server/src/queue/blueGreen/blueGreenReadinessChecks.ts b/server/src/queue/blueGreen/blueGreenReadinessChecks.ts index f9a827e2b..fb4174b28 100644 --- a/server/src/queue/blueGreen/blueGreenReadinessChecks.ts +++ b/server/src/queue/blueGreen/blueGreenReadinessChecks.ts @@ -1,9 +1,13 @@ -import { GetQueueAttributesCommand, type SQSClient } from "@aws-sdk/client-sqs"; +import { GetQueueAttributesCommand, SQSClient } from "@aws-sdk/client-sqs"; import type { DrizzleCli } from "@/db/initDrizzle.js"; +import { + DEFAULT_AWS_REGION, + extractRegionFromQueueUrl, +} from "@/external/aws/awsRegionUtils.js"; import { redis } from "@/external/redis/initRedis.js"; import { resolveRedisV2 } from "@/external/redis/resolveRedisV2.js"; import { withTimeout } from "@/utils/withTimeout.js"; -import { getSqsClient, QUEUE_URL } from "../initSqs.js"; +import { QUEUE_URL } from "../initSqs.js"; import type { BlueGreenProbeResult } from "./blueGreenSchemas.js"; const CHECK_TIMEOUT_MS = 5_000; @@ -41,6 +45,7 @@ const getConfiguredQueueUrls = () => QUEUE_URL, process.env.TRACK_SQS_QUEUE_URL, process.env.SQS_QUEUE_URL, + process.env.SQS_QUEUE_URL_V2, ].filter((url): url is string => Boolean(url)); export const getBlueGreenQueueUrls = ({ @@ -50,13 +55,27 @@ export const getBlueGreenQueueUrls = ({ } = {}) => Array.from(new Set([...getConfiguredQueueUrls(), ...knownQueueUrls])); +// Build a per-queue-URL SQSClient using the region extracted from the URL, +// so SigV4 signs against the queue's region. Reusing one singleton across +// queues in different regions fails with "Credential should be scoped to a +// valid region" because the client's region disagrees with the endpoint +// the SDK falls back to (the queue URL's host). +const sqsClientsByRegion = new Map(); +const getSqsClientForQueue = (queueUrl: string): SQSClient => { + const region = + extractRegionFromQueueUrl({ queueUrl }) ?? DEFAULT_AWS_REGION; + const cached = sqsClientsByRegion.get(region); + if (cached) return cached; + const client = new SQSClient({ region }); + sqsClientsByRegion.set(region, client); + return client; +}; + export const runBlueGreenReadinessChecks = async ({ db, - sqs = getSqsClient(), queueUrls = getBlueGreenQueueUrls(), }: { db: DrizzleCli; - sqs?: SQSClient; queueUrls?: string[]; }) => { const [dbCheck, redisCheck, redisV2Check, sqsCheck] = await Promise.all([ @@ -82,7 +101,7 @@ export const runBlueGreenReadinessChecks = async ({ } await Promise.all( queueUrls.map((queueUrl) => - sqs.send( + getSqsClientForQueue(queueUrl).send( new GetQueueAttributesCommand({ QueueUrl: queueUrl, AttributeNames: ["ApproximateNumberOfMessages"],