Skip to content

Commit

Permalink
feat(wrangler): add a new queues update command
Browse files Browse the repository at this point in the history
  • Loading branch information
TaraGarg authored and sdnts committed Feb 13, 2025
1 parent bc152ff commit 256f9d8
Show file tree
Hide file tree
Showing 5 changed files with 347 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/early-melons-deny.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wrangler": minor
---

Add a new `update` subcommand for Queues to allow updating Queue settings
212 changes: 212 additions & 0 deletions packages/wrangler/src/__tests__/queues.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ describe("wrangler", () => {
COMMANDS
wrangler queues list List Queues
wrangler queues create <name> Create a Queue
wrangler queues update <name> Update a Queue
wrangler queues delete <name> Delete a Queue
wrangler queues info <name> Get Queue information
wrangler queues consumer Configure Queue consumers
Expand Down Expand Up @@ -413,6 +414,217 @@ describe("wrangler", () => {
expect(requests.count).toEqual(0);
});
});

describe("update", () => {
function mockUpdateRequest(
queueName: string,
queueSettings:
| { delivery_delay?: number; message_retention_period?: number }
| undefined = undefined
) {
const requests = { count: 0 };

msw.use(
http.patch(
"*/accounts/:accountId/queues/:queueId",
async ({ request }) => {
requests.count += 1;

const body = (await request.json()) as {
queue_name: string;
settings: {
delivery_delay: number;
message_retention_period: number;
};
};
expect(body.queue_name).toEqual(queueName);
expect(body.settings).toEqual(queueSettings);
return HttpResponse.json({
success: true,
errors: [],
messages: [],
result: {
queue_name: queueName,
created_on: "01-01-2001",
modified_on: "01-01-2001",
},
});
},
{ once: true }
)
);
return requests;
}
function mockGetQueueRequest(
queueName: string,
queueSettings: {
delivery_delay: number;
message_retention_period: number;
}
) {
const requests = { count: 0 };
msw.use(
http.get(
"*/accounts/:accountId/queues?*",
async () => {
requests.count += 1;
return HttpResponse.json({
success: true,
errors: [],
messages: [],
result: [
{
queue_name: queueName,
created_on: "",
producers: [],
consumers: [],
producers_total_count: 1,
consumers_total_count: 0,
modified_on: "",
queue_id: "queueId",
settings: {
delivery_delay: queueSettings.delivery_delay,
message_retention_period:
queueSettings.message_retention_period,
},
},
],
});
},
{ once: true }
)
);
return requests;
}

it("should show the correct help text", async () => {
await runWrangler("queues update --help");
expect(std.err).toMatchInlineSnapshot(`""`);
expect(std.out).toMatchInlineSnapshot(`
"wrangler queues update <name>
Update a Queue
POSITIONALS
name The name of the queue [string] [required]
GLOBAL FLAGS
-c, --config Path to Wrangler configuration file [string]
-e, --env Environment to use for operations, and for selecting .env and .dev.vars files [string]
-h, --help Show help [boolean]
-v, --version Show version number [boolean]
OPTIONS
--delivery-delay-secs How long a published message should be delayed for, in seconds. Must be between 0 and 42300 [number]
--message-retention-period-secs How long to retain a message in the queue, in seconds. Must be between 60 and 1209600 [number]"
`);
});

it("should update a queue with new message retention period and preserve old delivery delay", async () => {
const getrequests = mockGetQueueRequest("testQueue", {
delivery_delay: 10,
message_retention_period: 100,
});

//update queue with new message retention period
const requests = mockUpdateRequest("testQueue", {
delivery_delay: 10,
message_retention_period: 400,
});
await runWrangler(
"queues update testQueue --message-retention-period-secs=400"
);

expect(requests.count).toEqual(1);
expect(getrequests.count).toEqual(1);

expect(std.out).toMatchInlineSnapshot(`
"Updating queue testQueue.
Updated queue testQueue."
`);
});

it("should show an error when two message retention periods are set", async () => {
const requests = mockUpdateRequest("testQueue", {
message_retention_period: 60,
});

mockGetQueueRequest("testQueue", {
delivery_delay: 0,
message_retention_period: 100,
});

await expect(
runWrangler(
"queues update testQueue --message-retention-period-secs=70 --message-retention-period-secs=80"
)
).rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: Cannot specify --message-retention-period-secs multiple times]`
);

expect(requests.count).toEqual(0);
});

it("should show an error when two delivery delays are set", async () => {
const requests = mockUpdateRequest("testQueue", {
delivery_delay: 10,
});

mockGetQueueRequest("testQueue", {
delivery_delay: 0,
message_retention_period: 100,
});

await expect(
runWrangler(
"queues update testQueue --delivery-delay-secs=5 --delivery-delay-secs=10"
)
).rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: Cannot specify --delivery-delay-secs multiple times]`
);

expect(requests.count).toEqual(0);
});

it("should show an error when invalid delivery delay is set", async () => {
const requests = mockUpdateRequest("testQueue", {
delivery_delay: 10,
});

mockGetQueueRequest("testQueue", {
delivery_delay: 0,
message_retention_period: 100,
});

await expect(
runWrangler("queues update testQueue --delivery-delay-secs=99999")
).rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: Invalid --delivery-delay-secs value: 99999. Must be between 0 and 43200]`
);

expect(requests.count).toEqual(0);
});

it("should show an error when invalid message retention period is set", async () => {
const requests = mockUpdateRequest("testQueue", {
message_retention_period: 100,
});

mockGetQueueRequest("testQueue", {
delivery_delay: 0,
message_retention_period: 100,
});

await expect(
runWrangler(
"queues update testQueue --message-retention-period-secs=0"
)
).rejects.toThrowErrorMatchingInlineSnapshot(
`[Error: Invalid --message-retention-period-secs value: 0. Must be between 60 and 1209600]`
);

expect(requests.count).toEqual(0);
});
});

describe("delete", () => {
Expand Down
8 changes: 8 additions & 0 deletions packages/wrangler/src/queues/cli/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { handler as createHandler, options as createOptions } from "./create";
import { handler as deleteHandler, options as deleteOptions } from "./delete";
import { handler as infoHandler, options as infoOptions } from "./info";
import { handler as listHandler, options as listOptions } from "./list";
import { handler as updateHandler, options as updateOptions } from "./update";
import type { CommonYargsArgv } from "../../../yargs-types";

export function queues(yargs: CommonYargsArgv) {
Expand All @@ -16,6 +17,13 @@ export function queues(yargs: CommonYargsArgv) {
createHandler
);

yargs.command(
"update <name>",
"Update a Queue",
updateOptions,
updateHandler
);

yargs.command(
"delete <name>",
"Delete a Queue",
Expand Down
110 changes: 110 additions & 0 deletions packages/wrangler/src/queues/cli/commands/update.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { readConfig } from "../../../config";
import { CommandLineArgsError } from "../../../errors";
import { logger } from "../../../logger";
import { getQueue, updateQueue } from "../../client";
import {
MAX_DELIVERY_DELAY_SECS,
MAX_MESSAGE_RETENTION_PERIOD_SECS,
MIN_DELIVERY_DELAY_SECS,
MIN_MESSAGE_RETENTION_PERIOD_SECS,
} from "../../constants";
import { handleFetchError } from "../../utils";
import type {
CommonYargsArgv,
StrictYargsOptionsToInterface,
} from "../../../yargs-types";
import type { PostQueueBody, QueueSettings } from "../../client";

export function options(yargs: CommonYargsArgv) {
return yargs
.positional("name", {
type: "string",
demandOption: true,
description: "The name of the queue",
})
.options({
"delivery-delay-secs": {
type: "number",
describe:
"How long a published message should be delayed for, in seconds. Must be between 0 and 42300",
},
"message-retention-period-secs": {
type: "number",
describe:
"How long to retain a message in the queue, in seconds. Must be between 60 and 1209600",
},
});
}

function updateBody(
args: StrictYargsOptionsToInterface<typeof options>,
currentSettings?: QueueSettings
): PostQueueBody {
const body: PostQueueBody = {
queue_name: args.name,
};

if (Array.isArray(args.deliveryDelaySecs)) {
throw new CommandLineArgsError(
"Cannot specify --delivery-delay-secs multiple times"
);
}

if (Array.isArray(args.messageRetentionPeriodSecs)) {
throw new CommandLineArgsError(
"Cannot specify --message-retention-period-secs multiple times"
);
}

body.settings = {};

if (args.deliveryDelaySecs != undefined) {
if (
args.deliveryDelaySecs < MIN_DELIVERY_DELAY_SECS ||
args.deliveryDelaySecs > MAX_DELIVERY_DELAY_SECS
) {
throw new CommandLineArgsError(
`Invalid --delivery-delay-secs value: ${args.deliveryDelaySecs}. Must be between ${MIN_DELIVERY_DELAY_SECS} and ${MAX_DELIVERY_DELAY_SECS}`
);
}
body.settings.delivery_delay = args.deliveryDelaySecs;
} else if (currentSettings?.delivery_delay != undefined) {
body.settings.delivery_delay = currentSettings.delivery_delay;
}

if (args.messageRetentionPeriodSecs != undefined) {
if (
args.messageRetentionPeriodSecs < MIN_MESSAGE_RETENTION_PERIOD_SECS ||
args.messageRetentionPeriodSecs > MAX_MESSAGE_RETENTION_PERIOD_SECS
) {
throw new CommandLineArgsError(
`Invalid --message-retention-period-secs value: ${args.messageRetentionPeriodSecs}. Must be between ${MIN_MESSAGE_RETENTION_PERIOD_SECS} and ${MAX_MESSAGE_RETENTION_PERIOD_SECS}`
);
}
body.settings.message_retention_period = args.messageRetentionPeriodSecs;
} else if (currentSettings?.message_retention_period != undefined) {
body.settings.message_retention_period =
currentSettings.message_retention_period;
}

if (Object.keys(body.settings).length === 0) {
body.settings = undefined;
}

return body;
}

export async function handler(
args: StrictYargsOptionsToInterface<typeof options>
) {
const config = readConfig(args);
try {
const currentQueue = await getQueue(config, args.name);
const body = updateBody(args, currentQueue.settings);
logger.log(`Updating queue ${args.name}.`);
await updateQueue(config, body, currentQueue.queue_id);
logger.log(`Updated queue ${args.name}.`);
} catch (e) {
handleFetchError(e as { code?: number });
}
}
12 changes: 12 additions & 0 deletions packages/wrangler/src/queues/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,18 @@ export async function createQueue(
});
}

export async function updateQueue(
config: Config,
body: PostQueueBody,
queue_id: string
): Promise<QueueResponse> {
const accountId = await requireAuth(config);
return fetchResult(queuesUrl(accountId, queue_id), {
method: "PATCH",
body: JSON.stringify(body),
});
}

export async function deleteQueue(
config: Config,
queueName: string
Expand Down

0 comments on commit 256f9d8

Please sign in to comment.