Files
2026-07-13 13:32:57 +08:00

288 lines
8.2 KiB
TypeScript

import type { MarQSKeyProducer, MarQSKeyProducerEnv, QueueDescriptor } from "./types";
const constants = {
SHARED_QUEUE: "sharedQueue",
SHARED_WORKER_QUEUE: "sharedWorkerQueue",
CURRENT_CONCURRENCY_PART: "currentConcurrency",
CONCURRENCY_LIMIT_PART: "concurrency",
DISABLED_CONCURRENCY_LIMIT_PART: "disabledConcurrency",
ENV_PART: "env",
ORG_PART: "org",
QUEUE_PART: "queue",
CONCURRENCY_KEY_PART: "ck",
MESSAGE_PART: "message",
RESERVE_CONCURRENCY_PART: "reserveConcurrency",
} as const;
const ORG_REGEX = /org:([^:]+):/;
const ENV_REGEX = /env:([^:]+):/;
const QUEUE_REGEX = /queue:([^:]+)(?::|$)/;
const CONCURRENCY_KEY_REGEX = /ck:([^:]+)(?::|$)/;
export class MarQSShortKeyProducer implements MarQSKeyProducer {
constructor(private _prefix: string) {}
sharedQueueScanPattern() {
return `${this._prefix}*${constants.SHARED_QUEUE}`;
}
queueCurrentConcurrencyScanPattern() {
return `${this._prefix}${constants.ORG_PART}:*:${constants.ENV_PART}:*:queue:*:${constants.CURRENT_CONCURRENCY_PART}`;
}
stripKeyPrefix(key: string): string {
if (key.startsWith(this._prefix)) {
return key.slice(this._prefix.length);
}
return key;
}
queueConcurrencyLimitKey(env: MarQSKeyProducerEnv, queue: string) {
return [this.queueKey(env, queue), constants.CONCURRENCY_LIMIT_PART].join(":");
}
envConcurrencyLimitKey(envId: string): string;
envConcurrencyLimitKey(env: MarQSKeyProducerEnv): string;
envConcurrencyLimitKey(envOrId: MarQSKeyProducerEnv | string): string {
return [
this.envKeySection(typeof envOrId === "string" ? envOrId : envOrId.id),
constants.CONCURRENCY_LIMIT_PART,
].join(":");
}
queueKey(orgId: string, envId: string, queue: string, concurrencyKey?: string): string;
queueKey(env: MarQSKeyProducerEnv, queue: string, concurrencyKey?: string): string;
queueKey(
envOrOrgId: MarQSKeyProducerEnv | string,
queueOrEnvId: string,
queueOrConcurrencyKey: string,
concurrencyKeyOrPriority?: string | number
): string {
if (typeof envOrOrgId === "string") {
return [
this.orgKeySection(envOrOrgId),
this.envKeySection(queueOrEnvId),
this.queueSection(queueOrConcurrencyKey),
]
.concat(
typeof concurrencyKeyOrPriority === "string"
? this.concurrencyKeySection(concurrencyKeyOrPriority)
: []
)
.join(":");
} else {
return [
this.orgKeySection(envOrOrgId.organizationId),
this.envKeySection(envOrOrgId.id),
this.queueSection(queueOrEnvId),
]
.concat(queueOrConcurrencyKey ? this.concurrencyKeySection(queueOrConcurrencyKey) : [])
.join(":");
}
}
queueKeyFromQueue(queue: string): string {
const descriptor = this.queueDescriptorFromQueue(queue);
return this.queueKey(
descriptor.organization,
descriptor.environment,
descriptor.name,
descriptor.concurrencyKey
);
}
envSharedQueueKey(env: MarQSKeyProducerEnv) {
if (env.type === "DEVELOPMENT") {
return [
this.orgKeySection(env.organizationId),
this.envKeySection(env.id),
constants.SHARED_QUEUE,
].join(":");
}
return this.sharedQueueKey();
}
sharedQueueKey(): string {
return constants.SHARED_QUEUE;
}
sharedWorkerQueueKey(): string {
return constants.SHARED_WORKER_QUEUE;
}
queueConcurrencyLimitKeyFromQueue(queue: string) {
const descriptor = this.queueDescriptorFromQueue(queue);
return this.queueConcurrencyLimitKeyFromDescriptor(descriptor);
}
queueCurrentConcurrencyKeyFromQueue(queue: string) {
const descriptor = this.queueDescriptorFromQueue(queue);
return this.currentConcurrencyKeyFromDescriptor(descriptor);
}
queueReserveConcurrencyKeyFromQueue(queue: string) {
const descriptor = this.queueDescriptorFromQueue(queue);
return this.queueReserveConcurrencyKeyFromDescriptor(descriptor);
}
queueCurrentConcurrencyKey(
env: MarQSKeyProducerEnv,
queue: string,
concurrencyKey?: string
): string {
return [this.queueKey(env, queue, concurrencyKey), constants.CURRENT_CONCURRENCY_PART].join(
":"
);
}
envConcurrencyLimitKeyFromQueue(queue: string) {
const descriptor = this.queueDescriptorFromQueue(queue);
return `${constants.ENV_PART}:${descriptor.environment}:${constants.CONCURRENCY_LIMIT_PART}`;
}
envCurrentConcurrencyKeyFromQueue(queue: string) {
const descriptor = this.queueDescriptorFromQueue(queue);
return `${constants.ENV_PART}:${descriptor.environment}:${constants.CURRENT_CONCURRENCY_PART}`;
}
envReserveConcurrencyKeyFromQueue(queue: string) {
const descriptor = this.queueDescriptorFromQueue(queue);
return this.envReserveConcurrencyKey(descriptor.environment);
}
envReserveConcurrencyKey(envId: string): string {
return `${constants.ENV_PART}:${this.shortId(envId)}:${constants.RESERVE_CONCURRENCY_PART}`;
}
envCurrentConcurrencyKey(envId: string): string;
envCurrentConcurrencyKey(env: MarQSKeyProducerEnv): string;
envCurrentConcurrencyKey(envOrId: MarQSKeyProducerEnv | string): string {
return [
this.envKeySection(typeof envOrId === "string" ? envOrId : envOrId.id),
constants.CURRENT_CONCURRENCY_PART,
].join(":");
}
envQueueKeyFromQueue(queue: string) {
const descriptor = this.queueDescriptorFromQueue(queue);
return `${constants.ENV_PART}:${descriptor.environment}:${constants.QUEUE_PART}`;
}
envQueueKey(env: MarQSKeyProducerEnv): string {
return [constants.ENV_PART, this.shortId(env.id), constants.QUEUE_PART].join(":");
}
messageKey(messageId: string) {
return `${constants.MESSAGE_PART}:${messageId}`;
}
nackCounterKey(messageId: string): string {
return `${constants.MESSAGE_PART}:${messageId}:nacks`;
}
orgIdFromQueue(queue: string) {
const descriptor = this.queueDescriptorFromQueue(queue);
return descriptor.organization;
}
envIdFromQueue(queue: string) {
const descriptor = this.queueDescriptorFromQueue(queue);
return descriptor.environment;
}
queueDescriptorFromQueue(queue: string): QueueDescriptor {
const match = queue.match(QUEUE_REGEX);
if (!match) {
throw new Error(`Invalid queue: ${queue}, no queue name found`);
}
const [, queueName] = match;
const envMatch = queue.match(ENV_REGEX);
if (!envMatch) {
throw new Error(`Invalid queue: ${queue}, no environment found`);
}
const [, envId] = envMatch;
const orgMatch = queue.match(ORG_REGEX);
if (!orgMatch) {
throw new Error(`Invalid queue: ${queue}, no organization found`);
}
const [, orgId] = orgMatch;
const concurrencyKeyMatch = queue.match(CONCURRENCY_KEY_REGEX);
const concurrencyKey = concurrencyKeyMatch ? concurrencyKeyMatch[1] : undefined;
return {
name: queueName,
environment: envId,
organization: orgId,
concurrencyKey,
};
}
private shortId(id: string) {
// Return the last 12 characters of the id
return id.slice(-12);
}
private envKeySection(envId: string) {
return `${constants.ENV_PART}:${this.shortId(envId)}`;
}
private orgKeySection(orgId: string) {
return `${constants.ORG_PART}:${this.shortId(orgId)}`;
}
private queueSection(queue: string) {
return `${constants.QUEUE_PART}:${queue}`;
}
private concurrencyKeySection(concurrencyKey: string) {
return `${constants.CONCURRENCY_KEY_PART}:${concurrencyKey}`;
}
private currentConcurrencyKeyFromDescriptor(descriptor: QueueDescriptor) {
return [
this.queueKey(
descriptor.organization,
descriptor.environment,
descriptor.name,
descriptor.concurrencyKey
),
constants.CURRENT_CONCURRENCY_PART,
].join(":");
}
private queueReserveConcurrencyKeyFromDescriptor(descriptor: QueueDescriptor) {
return [
this.queueKey(descriptor.organization, descriptor.environment, descriptor.name),
constants.RESERVE_CONCURRENCY_PART,
].join(":");
}
private queueConcurrencyLimitKeyFromDescriptor(descriptor: QueueDescriptor) {
return [
this.queueKey(descriptor.organization, descriptor.environment, descriptor.name),
constants.CONCURRENCY_LIMIT_PART,
].join(":");
}
}