Skip to content

Commit 6acf1f4

Browse files
TaraGargsdnts
authored andcommitted
feat(wrangler): add a new queues update command
1 parent e5874bc commit 6acf1f4

File tree

5 files changed

+347
-0
lines changed

5 files changed

+347
-0
lines changed

.changeset/early-melons-deny.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"wrangler": minor
3+
---
4+
5+
Add a new `update` subcommand for Queues to allow updating Queue settings

packages/wrangler/src/__tests__/queues.test.ts

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ describe("wrangler", () => {
2929
COMMANDS
3030
wrangler queues list List Queues
3131
wrangler queues create <name> Create a Queue
32+
wrangler queues update <name> Update a Queue
3233
wrangler queues delete <name> Delete a Queue
3334
wrangler queues info <name> Get Queue information
3435
wrangler queues consumer Configure Queue consumers
@@ -413,6 +414,217 @@ describe("wrangler", () => {
413414
expect(requests.count).toEqual(0);
414415
});
415416
});
417+
418+
describe("update", () => {
419+
function mockUpdateRequest(
420+
queueName: string,
421+
queueSettings:
422+
| { delivery_delay?: number; message_retention_period?: number }
423+
| undefined = undefined
424+
) {
425+
const requests = { count: 0 };
426+
427+
msw.use(
428+
http.patch(
429+
"*/accounts/:accountId/queues/:queueId",
430+
async ({ request }) => {
431+
requests.count += 1;
432+
433+
const body = (await request.json()) as {
434+
queue_name: string;
435+
settings: {
436+
delivery_delay: number;
437+
message_retention_period: number;
438+
};
439+
};
440+
expect(body.queue_name).toEqual(queueName);
441+
expect(body.settings).toEqual(queueSettings);
442+
return HttpResponse.json({
443+
success: true,
444+
errors: [],
445+
messages: [],
446+
result: {
447+
queue_name: queueName,
448+
created_on: "01-01-2001",
449+
modified_on: "01-01-2001",
450+
},
451+
});
452+
},
453+
{ once: true }
454+
)
455+
);
456+
return requests;
457+
}
458+
function mockGetQueueRequest(
459+
queueName: string,
460+
queueSettings: {
461+
delivery_delay: number;
462+
message_retention_period: number;
463+
}
464+
) {
465+
const requests = { count: 0 };
466+
msw.use(
467+
http.get(
468+
"*/accounts/:accountId/queues?*",
469+
async () => {
470+
requests.count += 1;
471+
return HttpResponse.json({
472+
success: true,
473+
errors: [],
474+
messages: [],
475+
result: [
476+
{
477+
queue_name: queueName,
478+
created_on: "",
479+
producers: [],
480+
consumers: [],
481+
producers_total_count: 1,
482+
consumers_total_count: 0,
483+
modified_on: "",
484+
queue_id: "queueId",
485+
settings: {
486+
delivery_delay: queueSettings.delivery_delay,
487+
message_retention_period:
488+
queueSettings.message_retention_period,
489+
},
490+
},
491+
],
492+
});
493+
},
494+
{ once: true }
495+
)
496+
);
497+
return requests;
498+
}
499+
500+
it("should show the correct help text", async () => {
501+
await runWrangler("queues update --help");
502+
expect(std.err).toMatchInlineSnapshot(`""`);
503+
expect(std.out).toMatchInlineSnapshot(`
504+
"wrangler queues update <name>
505+
506+
Update a Queue
507+
508+
POSITIONALS
509+
name The name of the queue [string] [required]
510+
511+
GLOBAL FLAGS
512+
-c, --config Path to Wrangler configuration file [string]
513+
-e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string]
514+
-h, --help Show help [boolean]
515+
-v, --version Show version number [boolean]
516+
517+
OPTIONS
518+
--delivery-delay-secs How long a published message should be delayed for, in seconds. Must be between 0 and 42300 [number]
519+
--message-retention-period-secs How long to retain a message in the queue, in seconds. Must be between 60 and 1209600 [number]"
520+
`);
521+
});
522+
523+
it("should update a queue with new message retention period and preserve old delivery delay", async () => {
524+
const getrequests = mockGetQueueRequest("testQueue", {
525+
delivery_delay: 10,
526+
message_retention_period: 100,
527+
});
528+
529+
//update queue with new message retention period
530+
const requests = mockUpdateRequest("testQueue", {
531+
delivery_delay: 10,
532+
message_retention_period: 400,
533+
});
534+
await runWrangler(
535+
"queues update testQueue --message-retention-period-secs=400"
536+
);
537+
538+
expect(requests.count).toEqual(1);
539+
expect(getrequests.count).toEqual(1);
540+
541+
expect(std.out).toMatchInlineSnapshot(`
542+
"Updating queue testQueue.
543+
Updated queue testQueue."
544+
`);
545+
});
546+
547+
it("should show an error when two message retention periods are set", async () => {
548+
const requests = mockUpdateRequest("testQueue", {
549+
message_retention_period: 60,
550+
});
551+
552+
mockGetQueueRequest("testQueue", {
553+
delivery_delay: 0,
554+
message_retention_period: 100,
555+
});
556+
557+
await expect(
558+
runWrangler(
559+
"queues update testQueue --message-retention-period-secs=70 --message-retention-period-secs=80"
560+
)
561+
).rejects.toThrowErrorMatchingInlineSnapshot(
562+
`[Error: Cannot specify --message-retention-period-secs multiple times]`
563+
);
564+
565+
expect(requests.count).toEqual(0);
566+
});
567+
568+
it("should show an error when two delivery delays are set", async () => {
569+
const requests = mockUpdateRequest("testQueue", {
570+
delivery_delay: 10,
571+
});
572+
573+
mockGetQueueRequest("testQueue", {
574+
delivery_delay: 0,
575+
message_retention_period: 100,
576+
});
577+
578+
await expect(
579+
runWrangler(
580+
"queues update testQueue --delivery-delay-secs=5 --delivery-delay-secs=10"
581+
)
582+
).rejects.toThrowErrorMatchingInlineSnapshot(
583+
`[Error: Cannot specify --delivery-delay-secs multiple times]`
584+
);
585+
586+
expect(requests.count).toEqual(0);
587+
});
588+
589+
it("should show an error when invalid delivery delay is set", async () => {
590+
const requests = mockUpdateRequest("testQueue", {
591+
delivery_delay: 10,
592+
});
593+
594+
mockGetQueueRequest("testQueue", {
595+
delivery_delay: 0,
596+
message_retention_period: 100,
597+
});
598+
599+
await expect(
600+
runWrangler("queues update testQueue --delivery-delay-secs=99999")
601+
).rejects.toThrowErrorMatchingInlineSnapshot(
602+
`[Error: Invalid --delivery-delay-secs value: 99999. Must be between 0 and 43200]`
603+
);
604+
605+
expect(requests.count).toEqual(0);
606+
});
607+
608+
it("should show an error when invalid message retention period is set", async () => {
609+
const requests = mockUpdateRequest("testQueue", {
610+
message_retention_period: 100,
611+
});
612+
613+
mockGetQueueRequest("testQueue", {
614+
delivery_delay: 0,
615+
message_retention_period: 100,
616+
});
617+
618+
await expect(
619+
runWrangler(
620+
"queues update testQueue --message-retention-period-secs=0"
621+
)
622+
).rejects.toThrowErrorMatchingInlineSnapshot(
623+
`[Error: Invalid --message-retention-period-secs value: 0. Must be between 60 and 1209600]`
624+
);
625+
626+
expect(requests.count).toEqual(0);
627+
});
416628
});
417629

418630
describe("delete", () => {

packages/wrangler/src/queues/cli/commands/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { handler as createHandler, options as createOptions } from "./create";
44
import { handler as deleteHandler, options as deleteOptions } from "./delete";
55
import { handler as infoHandler, options as infoOptions } from "./info";
66
import { handler as listHandler, options as listOptions } from "./list";
7+
import { handler as updateHandler, options as updateOptions } from "./update";
78
import type { CommonYargsArgv } from "../../../yargs-types";
89

910
export function queues(yargs: CommonYargsArgv) {
@@ -16,6 +17,13 @@ export function queues(yargs: CommonYargsArgv) {
1617
createHandler
1718
);
1819

20+
yargs.command(
21+
"update <name>",
22+
"Update a Queue",
23+
updateOptions,
24+
updateHandler
25+
);
26+
1927
yargs.command(
2028
"delete <name>",
2129
"Delete a Queue",
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import { readConfig } from "../../../config";
2+
import { CommandLineArgsError } from "../../../errors";
3+
import { logger } from "../../../logger";
4+
import { getQueue, updateQueue } from "../../client";
5+
import {
6+
MAX_DELIVERY_DELAY_SECS,
7+
MAX_MESSAGE_RETENTION_PERIOD_SECS,
8+
MIN_DELIVERY_DELAY_SECS,
9+
MIN_MESSAGE_RETENTION_PERIOD_SECS,
10+
} from "../../constants";
11+
import { handleFetchError } from "../../utils";
12+
import type {
13+
CommonYargsArgv,
14+
StrictYargsOptionsToInterface,
15+
} from "../../../yargs-types";
16+
import type { PostQueueBody, QueueSettings } from "../../client";
17+
18+
export function options(yargs: CommonYargsArgv) {
19+
return yargs
20+
.positional("name", {
21+
type: "string",
22+
demandOption: true,
23+
description: "The name of the queue",
24+
})
25+
.options({
26+
"delivery-delay-secs": {
27+
type: "number",
28+
describe:
29+
"How long a published message should be delayed for, in seconds. Must be between 0 and 42300",
30+
},
31+
"message-retention-period-secs": {
32+
type: "number",
33+
describe:
34+
"How long to retain a message in the queue, in seconds. Must be between 60 and 1209600",
35+
},
36+
});
37+
}
38+
39+
function updateBody(
40+
args: StrictYargsOptionsToInterface<typeof options>,
41+
currentSettings?: QueueSettings
42+
): PostQueueBody {
43+
const body: PostQueueBody = {
44+
queue_name: args.name,
45+
};
46+
47+
if (Array.isArray(args.deliveryDelaySecs)) {
48+
throw new CommandLineArgsError(
49+
"Cannot specify --delivery-delay-secs multiple times"
50+
);
51+
}
52+
53+
if (Array.isArray(args.messageRetentionPeriodSecs)) {
54+
throw new CommandLineArgsError(
55+
"Cannot specify --message-retention-period-secs multiple times"
56+
);
57+
}
58+
59+
body.settings = {};
60+
61+
if (args.deliveryDelaySecs != undefined) {
62+
if (
63+
args.deliveryDelaySecs < MIN_DELIVERY_DELAY_SECS ||
64+
args.deliveryDelaySecs > MAX_DELIVERY_DELAY_SECS
65+
) {
66+
throw new CommandLineArgsError(
67+
`Invalid --delivery-delay-secs value: ${args.deliveryDelaySecs}. Must be between ${MIN_DELIVERY_DELAY_SECS} and ${MAX_DELIVERY_DELAY_SECS}`
68+
);
69+
}
70+
body.settings.delivery_delay = args.deliveryDelaySecs;
71+
} else if (currentSettings?.delivery_delay != undefined) {
72+
body.settings.delivery_delay = currentSettings.delivery_delay;
73+
}
74+
75+
if (args.messageRetentionPeriodSecs != undefined) {
76+
if (
77+
args.messageRetentionPeriodSecs < MIN_MESSAGE_RETENTION_PERIOD_SECS ||
78+
args.messageRetentionPeriodSecs > MAX_MESSAGE_RETENTION_PERIOD_SECS
79+
) {
80+
throw new CommandLineArgsError(
81+
`Invalid --message-retention-period-secs value: ${args.messageRetentionPeriodSecs}. Must be between ${MIN_MESSAGE_RETENTION_PERIOD_SECS} and ${MAX_MESSAGE_RETENTION_PERIOD_SECS}`
82+
);
83+
}
84+
body.settings.message_retention_period = args.messageRetentionPeriodSecs;
85+
} else if (currentSettings?.message_retention_period != undefined) {
86+
body.settings.message_retention_period =
87+
currentSettings.message_retention_period;
88+
}
89+
90+
if (Object.keys(body.settings).length === 0) {
91+
body.settings = undefined;
92+
}
93+
94+
return body;
95+
}
96+
97+
export async function handler(
98+
args: StrictYargsOptionsToInterface<typeof options>
99+
) {
100+
const config = readConfig(args);
101+
try {
102+
const currentQueue = await getQueue(config, args.name);
103+
const body = updateBody(args, currentQueue.settings);
104+
logger.log(`Updating queue ${args.name}.`);
105+
await updateQueue(config, body, currentQueue.queue_id);
106+
logger.log(`Updated queue ${args.name}.`);
107+
} catch (e) {
108+
handleFetchError(e as { code?: number });
109+
}
110+
}

packages/wrangler/src/queues/client.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,18 @@ export async function createQueue(
115115
});
116116
}
117117

118+
export async function updateQueue(
119+
config: Config,
120+
body: PostQueueBody,
121+
queue_id: string
122+
): Promise<QueueResponse> {
123+
const accountId = await requireAuth(config);
124+
return fetchResult(queuesUrl(accountId, queue_id), {
125+
method: "PATCH",
126+
body: JSON.stringify(body),
127+
});
128+
}
129+
118130
export async function deleteQueue(
119131
config: Config,
120132
queueName: string

0 commit comments

Comments
 (0)