From 251724362b67e1408639658d5456deda20991638 Mon Sep 17 00:00:00 2001 From: Nikita Sharma Date: Mon, 14 Jul 2025 10:43:02 -0500 Subject: [PATCH 1/9] Add support for custom instance types Custom instance types could previously only be set through setting vcpu/memory/disk through the `configuration` block. As we deprecate `configuration`, move setting vcpu, memory, and disk to the instance type field of wrangler. By nature, this enforces that custom instance types are mutually exclusive with the named instance types and will allow us to remove a lot of the logic that verifies this once `configuration` is removed. --- .changeset/hungry-turtles-beam.md | 5 + .../src/__tests__/cloudchamber/apply.test.ts | 147 ++++++++++++++++++ packages/wrangler/src/cloudchamber/apply.ts | 28 +++- packages/wrangler/src/config/environment.ts | 10 +- packages/wrangler/src/config/validation.ts | 62 ++++++-- 5 files changed, 233 insertions(+), 19 deletions(-) create mode 100644 .changeset/hungry-turtles-beam.md diff --git a/.changeset/hungry-turtles-beam.md b/.changeset/hungry-turtles-beam.md new file mode 100644 index 000000000000..0bbb9de12820 --- /dev/null +++ b/.changeset/hungry-turtles-beam.md @@ -0,0 +1,5 @@ +--- +"wrangler": patch +--- + +Add support for custom instance types diff --git a/packages/wrangler/src/__tests__/cloudchamber/apply.test.ts b/packages/wrangler/src/__tests__/cloudchamber/apply.test.ts index ba8164b86618..72da77363ffd 100644 --- a/packages/wrangler/src/__tests__/cloudchamber/apply.test.ts +++ b/packages/wrangler/src/__tests__/cloudchamber/apply.test.ts @@ -1614,6 +1614,63 @@ describe("cloudchamber apply", () => { expect(std.stderr).toMatchInlineSnapshot(`""`); }); + test("can apply a simple application (custom instance type)", async () => { + setIsTTY(false); + writeWranglerConfig({ + name: "my-container", + containers: [ + { + name: "my-container-app", + instances: 3, + class_name: "DurableObjectClass", + instance_type: { + vcpu: 1, + memory_mib: 1024, + disk_mb: 2000, + }, + image: "docker.io/beep:boop", + constraints: { + tier: 2, + }, + }, + ], + }); + mockGetApplications([]); + mockCreateApplication({ id: "abc" }); + await runWrangler("cloudchamber apply"); + expect(std.stdout).toMatchInlineSnapshot(` + "╭ Deploy a container application deploy changes to your application + │ + │ Container application changes + │ + ├ NEW my-container-app + │ + │ [[containers]] + │ name = \\"my-container-app\\" + │ instances = 3 + │ scheduling_policy = \\"default\\" + │ + │ [containers.constraints] + │ tier = 2 + │ + │ [containers.configuration] + │ image = \\"docker.io/beep:boop\\" + │ vcpu = 1 + │ memory_mib = 1_024 + │ + │ [containers.configuration.disk] + │ size_mb = 2_000 + │ + │ + │ SUCCESS Created application my-container-app (Application ID: abc) + │ + ╰ Applied changes + + " + `); + expect(std.stderr).toMatchInlineSnapshot(`""`); + }); + test("can apply a simple existing application (instance type)", async () => { setIsTTY(false); writeWranglerConfig({ @@ -1691,6 +1748,96 @@ describe("cloudchamber apply", () => { expect(app.configuration?.instance_type).toEqual("standard"); }); + test("can apply a simple existing application (custom instance type)", async () => { + setIsTTY(false); + writeWranglerConfig({ + name: "my-container", + containers: [ + { + name: "my-container-app", + instances: 4, + class_name: "DurableObjectClass", + instance_type: { + vcpu: 1, + memory_mib: 1024, + disk_mb: 6000, + }, + image: "docker.io/beep:boop", + constraints: { + tier: 2, + }, + }, + ], + }); + mockGetApplications([ + { + id: "abc", + name: "my-container-app", + instances: 3, + created_at: new Date().toString(), + version: 1, + account_id: "1", + scheduling_policy: SchedulingPolicy.REGIONAL, + configuration: { + image: "docker.io/beep:boop", + disk: { + size: "2GB", + size_mb: 2000, + }, + vcpu: 0.0625, + memory: "256MB", + memory_mib: 256, + }, + constraints: { + tier: 3, + }, + }, + ]); + const applicationReqBodyPromise = mockModifyApplication(); + await runWrangler("cloudchamber apply"); + expect(std.stdout).toMatchInlineSnapshot(` + "╭ Deploy a container application deploy changes to your application + │ + │ Container application changes + │ + ├ EDIT my-container-app + │ + │ [[containers]] + │ - instances = 3 + │ + instances = 4 + │ name = \\"my-container-app\\" + │ scheduling_policy = \\"regional\\" + │ + │ [containers.configuration] + │ image = \\"docker.io/beep:boop\\" + │ memory = \\"256MB\\" + │ - memory_mib = 256 + │ + memory_mib = 1_024 + │ + │ - vcpu = 0.0625 + │ + vcpu = 1 + │ + │ [containers.configuration.disk] + │ size = \\"2GB\\" + │ - size_mb = 2_000 + │ + size_mb = 6_000 + │ + │ [containers.constraints] + │ - tier = 3 + │ + tier = 2 + │ + │ + │ SUCCESS Modified application my-container-app + │ + ╰ Applied changes + + " + `); + expect(std.stderr).toMatchInlineSnapshot(`""`); + const app = await applicationReqBodyPromise; + expect(app.configuration?.instance_type).toBeUndefined(); + }); + test("falls back on dev instance type when instance type is absent", async () => { setIsTTY(false); writeWranglerConfig({ diff --git a/packages/wrangler/src/cloudchamber/apply.ts b/packages/wrangler/src/cloudchamber/apply.ts index 600c666fe40d..1a655af21847 100644 --- a/packages/wrangler/src/cloudchamber/apply.ts +++ b/packages/wrangler/src/cloudchamber/apply.ts @@ -188,22 +188,34 @@ function observabilityToConfiguration( function containerAppToInstanceType( containerApp: ContainerApp -): InstanceType | undefined { +): Partial { + let configuration = (containerApp.configuration ?? + {}) as Partial; + if (containerApp.instance_type !== undefined) { - return containerApp.instance_type as InstanceType; + if (typeof containerApp.instance_type === "string") { + return { instance_type: containerApp.instance_type as InstanceType }; + } + + configuration = { + vcpu: containerApp.instance_type.vcpu, + memory_mib: containerApp.instance_type.memory_mib, + disk: { + size_mb: containerApp.instance_type.disk_mb, + }, + }; } // if no other configuration is set, we fall back to the default "dev" instance type - const configuration = - containerApp.configuration as UserDeploymentConfiguration; if ( - configuration.disk === undefined && + configuration.disk?.size_mb === undefined && configuration.vcpu === undefined && - configuration.memory === undefined && configuration.memory_mib === undefined ) { - return InstanceType.DEV; + return { instance_type: InstanceType.DEV }; } + + return configuration; } function containerAppToCreateApplication( @@ -220,8 +232,8 @@ function containerAppToCreateApplication( const instanceType = containerAppToInstanceType(containerApp); const configuration: UserDeploymentConfiguration = { ...(containerApp.configuration as UserDeploymentConfiguration), + ...instanceType, observability: observabilityConfiguration, - instance_type: instanceType, }; // this should have been set to a default value of worker-name-class-name if unspecified by the user diff --git a/packages/wrangler/src/config/environment.ts b/packages/wrangler/src/config/environment.ts index 7ec0ab22c939..0bb24d198f11 100644 --- a/packages/wrangler/src/config/environment.ts +++ b/packages/wrangler/src/config/environment.ts @@ -103,7 +103,15 @@ export type ContainerApp = { * @optional * @default "dev" */ - instance_type?: "dev" | "basic" | "standard"; + instance_type?: + | "dev" + | "basic" + | "standard" + | { + vcpu?: number; + memory_mib?: number; + disk_mb?: number; + }; /** * @deprecated Use top level `containers` fields instead. diff --git a/packages/wrangler/src/config/validation.ts b/packages/wrangler/src/config/validation.ts index 3452cc439a3c..03872401fd3f 100644 --- a/packages/wrangler/src/config/validation.ts +++ b/packages/wrangler/src/config/validation.ts @@ -2428,13 +2428,13 @@ function validateContainerApp( !containerAppOptional.image ) { diagnostics.errors.push( - `"containers.image" field must be defined for each container app. This should be the path to your Dockerfile or a image URI pointing to the Cloudflare registry.` + `"containers.image" field must be defined for each container app. This should be the path to your Dockerfile or an image URI pointing to the Cloudflare registry.` ); } if ("configuration" in containerAppOptional) { diagnostics.warnings.push( - `"containers.configuration" is deprecated. Use top level "containers" fields instead. "configuration.image" should be "image", "configuration.disk" should be set via "instance_type".` + `"containers.configuration" is deprecated. Use top level "containers" fields instead. "configuration.image" should be "image", limits should be set via "instance_type".` ); if ( typeof containerAppOptional.configuration !== "object" || @@ -2509,14 +2509,6 @@ function validateContainerApp( "string", ["full_auto", "full_manual", "none"] ); - validateOptionalProperty( - diagnostics, - field, - "instance_type", - containerAppOptional.instance_type, - "string", - ["dev", "basic", "standard"] - ); validateOptionalProperty( diagnostics, field, @@ -2589,6 +2581,56 @@ function validateContainerApp( ["image", "secrets", "labels", "disk", "vcpu", "memory_mib"] ); } + + // Instance Type validation: When present, the instance type should be either (1) a string + // representing a predefined instance type or (2) an object that optionally defines vcpu, + // memory, and disk. + // + // If an instance type is not set, a 'dev' instance type will be used. If a custom instance + // type doesn't set a value, that value will default to the corresponding value in a 'dev' + // instance type + if (typeof containerAppOptional.instance_type === "string") { + // validate named instance type + validateOptionalProperty( + diagnostics, + field, + "instance_type", + containerAppOptional.instance_type, + "string", + ["dev", "basic", "standard"] + ); + } else if ( + validateOptionalProperty( + diagnostics, + field, + "instance_type", + containerAppOptional.instance_type, + "object" + ) && + containerAppOptional.instance_type + ) { + // validate custom instance type + const instanceTypeProperties = ["vcpu", "memory_mib", "disk_mb"]; + instanceTypeProperties.forEach((key) => { + if ( + !isOptionalProperty( + containerAppOptional.instance_type, + key, + "number" + ) + ) { + diagnostics.errors.push( + `"containers.instance_type.${key}", when present, should be a number.` + ); + } + }); + validateAdditionalProperties( + diagnostics, + `${field}.instance_type`, + Object.keys(containerAppOptional.instance_type), + instanceTypeProperties + ); + } } if (diagnostics.errors.length > 0) { From b84b367b929d630a0b5943d42e77a028cde83c3f Mon Sep 17 00:00:00 2001 From: Nikita Sharma Date: Wed, 23 Jul 2025 13:05:41 -0500 Subject: [PATCH 2/9] fix configuration test failures --- .../wrangler/src/__tests__/config/configuration.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/wrangler/src/__tests__/config/configuration.test.ts b/packages/wrangler/src/__tests__/config/configuration.test.ts index 2f276455dbf2..7f8541dc2238 100644 --- a/packages/wrangler/src/__tests__/config/configuration.test.ts +++ b/packages/wrangler/src/__tests__/config/configuration.test.ts @@ -2454,10 +2454,10 @@ describe("normalizeAndValidateConfig()", () => { - The image \\"something\\" does not appear to be a valid path to a Dockerfile, or a valid image registry path: If this is an image registry path, it needs to include at least a tag ':' (e.g: docker.io/httpd:1) - Expected \\"containers.rollout_kind\\" field to be one of [\\"full_auto\\",\\"full_manual\\",\\"none\\"] but got \\"invalid\\". - - Expected \\"containers.instance_type\\" field to be one of [\\"dev\\",\\"basic\\",\\"standard\\"] but got \\"invalid\\". - Expected \\"containers.max_instances\\" to be of type number but got \\"invalid\\". - Expected \\"containers.image_vars\\" to be of type object but got \\"invalid\\". - - Expected \\"containers.scheduling_policy\\" field to be one of [\\"regional\\",\\"moon\\",\\"default\\"] but got \\"invalid\\"." + - Expected \\"containers.scheduling_policy\\" field to be one of [\\"regional\\",\\"moon\\",\\"default\\"] but got \\"invalid\\". + - Expected \\"containers.instance_type\\" field to be one of [\\"dev\\",\\"basic\\",\\"standard\\"] but got \\"invalid\\"." `); }); @@ -2485,7 +2485,7 @@ describe("normalizeAndValidateConfig()", () => { expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(` "Processing wrangler configuration: - - \\"containers.configuration\\" is deprecated. Use top level \\"containers\\" fields instead. \\"configuration.image\\" should be \\"image\\", \\"configuration.disk\\" should be set via \\"instance_type\\". + - \\"containers.configuration\\" is deprecated. Use top level \\"containers\\" fields instead. \\"configuration.image\\" should be \\"image\\", limits should be set via \\"instance_type\\". - \\"containers.instances\\" is deprecated. Use \\"containers.max_instances\\" instead. - \\"containers.durable_objects\\" is deprecated. Use the \\"class_name\\" field instead." `); @@ -2519,7 +2519,7 @@ describe("normalizeAndValidateConfig()", () => { expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(` "Processing wrangler configuration: - - \\"containers.configuration\\" is deprecated. Use top level \\"containers\\" fields instead. \\"configuration.image\\" should be \\"image\\", \\"configuration.disk\\" should be set via \\"instance_type\\". + - \\"containers.configuration\\" is deprecated. Use top level \\"containers\\" fields instead. \\"configuration.image\\" should be \\"image\\", limits should be set via \\"instance_type\\". - Unexpected fields found in containers.configuration field: \\"memory\\",\\"invalid_field\\",\\"another_invalid\\"" `); }); From 5da03d241643051cf0da9b0e1825260954f37611 Mon Sep 17 00:00:00 2001 From: Nikita Sharma Date: Mon, 28 Jul 2025 12:03:25 -0500 Subject: [PATCH 3/9] update changeset --- .changeset/hungry-turtles-beam.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/hungry-turtles-beam.md b/.changeset/hungry-turtles-beam.md index 0bbb9de12820..dfe9942c5c8e 100644 --- a/.changeset/hungry-turtles-beam.md +++ b/.changeset/hungry-turtles-beam.md @@ -2,4 +2,4 @@ "wrangler": patch --- -Add support for custom instance types +Add support for custom instance types for users without the `REQUIRE_INSTANCE_TYPE` capability From cbdba1bb86103150752cd7ea3abc7e667fd0268f Mon Sep 17 00:00:00 2001 From: Nikita Sharma Date: Mon, 28 Jul 2025 14:09:48 -0500 Subject: [PATCH 4/9] normalize custom instance types --- packages/wrangler/src/containers/config.ts | 29 +++++++++++++++------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/packages/wrangler/src/containers/config.ts b/packages/wrangler/src/containers/config.ts index 9fde21b6c022..6258f0cb1cef 100644 --- a/packages/wrangler/src/containers/config.ts +++ b/packages/wrangler/src/containers/config.ts @@ -75,25 +75,36 @@ export const getNormalizedContainerOptions = async ( }, }; - let instanceTypeOrDisk: InstanceTypeOrLimits; - + let instanceTypeOrLimits: InstanceTypeOrLimits; + const MB = 1000 * 1000; if ( container.configuration?.disk !== undefined || container.configuration?.vcpu !== undefined || container.configuration?.memory_mib !== undefined ) { - const MB = 1000 * 1000; + // deprecated path to set a custom instance type // if an individual limit is not set, default to the dev instance type values - instanceTypeOrDisk = { - disk_bytes: (container.configuration.disk?.size_mb ?? 2000) * MB, // defaults to 2GB in bytes + instanceTypeOrLimits = { + disk_bytes: (container.configuration?.disk?.size_mb ?? 2000) * MB, // defaults to 2GB in bytes vcpu: container.configuration?.vcpu ?? 0.0625, memory_mib: container.configuration?.memory_mib ?? 256, }; - } else { - instanceTypeOrDisk = { + } else if ( + typeof container.instance_type === "string" || + container.instance_type === undefined + ) { + instanceTypeOrLimits = { instance_type: (container.instance_type ?? InstanceType.DEV) as InstanceType, }; + } else { + // set a custom instance type + // any limits that are not set will default to a dev instance type + instanceTypeOrLimits = { + disk_bytes: (container.instance_type.disk_mb ?? 2000) * MB, + vcpu: container.instance_type.vcpu ?? 0.0625, + memory_mib: container.instance_type.memory_mib ?? 256, + }; } const maybeDockerfile = isDockerfile(container.image, config.configPath); @@ -111,7 +122,7 @@ export const getNormalizedContainerOptions = async ( ); normalizedContainers.push({ ...shared, - ...instanceTypeOrDisk, + ...instanceTypeOrLimits, dockerfile: container.image, image_build_context: imageBuildContext, image_vars: container.image_vars, @@ -120,7 +131,7 @@ export const getNormalizedContainerOptions = async ( const accountId = await getAccountId(config); normalizedContainers.push({ ...shared, - ...instanceTypeOrDisk, + ...instanceTypeOrLimits, image_uri: resolveImageName(accountId, container.image), // if it is not a dockerfile, it must be an image uri or have thrown an error }); } From 17cba037cb93e5f728ce7ef9b48b01dad1f1eecc Mon Sep 17 00:00:00 2001 From: Nikita Sharma Date: Mon, 28 Jul 2025 14:10:00 -0500 Subject: [PATCH 5/9] add test for wrangler deploy --- .../src/__tests__/containers/deploy.test.ts | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/packages/wrangler/src/__tests__/containers/deploy.test.ts b/packages/wrangler/src/__tests__/containers/deploy.test.ts index fe15402130c7..2f6f7f2cff25 100644 --- a/packages/wrangler/src/__tests__/containers/deploy.test.ts +++ b/packages/wrangler/src/__tests__/containers/deploy.test.ts @@ -306,6 +306,91 @@ describe("wrangler deploy with containers", () => { `); }); + it("should be able to deploy a new container with custom instance limits (instance_type)", async () => { + // note no docker commands have been mocked here! + mockGetVersion("Galaxy-Class"); + writeWranglerConfig({ + ...DEFAULT_DURABLE_OBJECTS, + containers: [ + { + ...DEFAULT_CONTAINER_FROM_REGISTRY, + instance_type: { + vcpu: 1, + memory_mib: 1000, + disk_mb: 2000, + }, + }, + ], + }); + + mockGetApplications([]); + + mockCreateApplication({ + name: "my-container", + max_instances: 10, + scheduling_policy: SchedulingPolicy.DEFAULT, + configuration: { + image: "docker.io/hello:world", + disk: { + size_mb: 2000, + }, + vcpu: 1, + memory_mib: 1000, + }, + }); + + await runWrangler("deploy index.js"); + + expect(std.out).toMatchInlineSnapshot(` + "Total Upload: xx KiB / gzip: xx KiB + Worker Startup Time: 100 ms + Your Worker has access to the following bindings: + Binding Resource + env.EXAMPLE_DO_BINDING (ExampleDurableObject) Durable Object + + Uploaded test-name (TIMINGS) + Deployed test-name triggers (TIMINGS) + https://test-name.test-sub-domain.workers.dev + Current Version ID: Galaxy-Class" + `); + expect(std.err).toMatchInlineSnapshot(`""`); + + expect(cliStd.stdout).toMatchInlineSnapshot(` + "╭ Deploy a container application deploy changes to your application + │ + │ Container application changes + │ + ├ NEW my-container + │ + │ [[containers]] + │ name = \\"my-container\\" + │ scheduling_policy = \\"default\\" + │ instances = 0 + │ max_instances = 10 + │ + │ [containers.configuration] + │ image = \\"docker.io/hello:world\\" + │ memory_mib = 1_000 + │ vcpu = 1 + │ + │ [containers.configuration.disk] + │ size_mb = 2_000 + │ + │ [containers.constraints] + │ tier = 1 + │ + │ [containers.durable_objects] + │ namespace_id = \\"1\\" + │ + │ + │ SUCCESS Created application my-container (Application ID: undefined) + │ + ╰ Applied changes + + " + `); + }); + it("should resolve the docker build context path based on the dockerfile location, if image_build_context is not provided", async () => { vi.stubEnv("WRANGLER_DOCKER_BIN", "/usr/bin/docker"); mockGetVersion("Galaxy-Class"); From 1fed2ab7c161d91fe19a9f932f9f086946ba18a1 Mon Sep 17 00:00:00 2001 From: Nikita Sharma Date: Wed, 30 Jul 2025 09:16:40 -0500 Subject: [PATCH 6/9] update tests to specify deprecated path and updated path --- .../wrangler/src/__tests__/containers/deploy.test.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/wrangler/src/__tests__/containers/deploy.test.ts b/packages/wrangler/src/__tests__/containers/deploy.test.ts index 2f6f7f2cff25..172fe784dd0c 100644 --- a/packages/wrangler/src/__tests__/containers/deploy.test.ts +++ b/packages/wrangler/src/__tests__/containers/deploy.test.ts @@ -222,6 +222,7 @@ describe("wrangler deploy with containers", () => { }); it("should be able to deploy a new container with custom instance limits", async () => { + // this test checks the deprecated path for setting custom instance limits // note no docker commands have been mocked here! mockGetVersion("Galaxy-Class"); writeWranglerConfig({ @@ -268,6 +269,14 @@ describe("wrangler deploy with containers", () => { https://test-name.test-sub-domain.workers.dev Current Version ID: Galaxy-Class" `); + expect(std.warn).toMatchInlineSnapshot(` + "▲ [WARNING] Processing wrangler.toml configuration: + + - \\"containers.configuration\\" is deprecated. Use top level \\"containers\\" fields instead. + \\"configuration.image\\" should be \\"image\\", limits should be set via \\"instance_type\\". + + " + `); expect(std.err).toMatchInlineSnapshot(`""`); expect(cliStd.stdout).toMatchInlineSnapshot(` @@ -307,6 +316,7 @@ describe("wrangler deploy with containers", () => { }); it("should be able to deploy a new container with custom instance limits (instance_type)", async () => { + // tests the preferred method for setting custom instance limits // note no docker commands have been mocked here! mockGetVersion("Galaxy-Class"); writeWranglerConfig({ @@ -353,6 +363,8 @@ describe("wrangler deploy with containers", () => { https://test-name.test-sub-domain.workers.dev Current Version ID: Galaxy-Class" `); + // no deprecation warnings should show up on this run + expect(std.warn).toMatchInlineSnapshot(`""`); expect(std.err).toMatchInlineSnapshot(`""`); expect(cliStd.stdout).toMatchInlineSnapshot(` From de41b1833b4af717fb6e051eb4a998b9137bf9f4 Mon Sep 17 00:00:00 2001 From: Nikita Sharma Date: Wed, 30 Jul 2025 09:19:30 -0500 Subject: [PATCH 7/9] update changeset --- .changeset/hungry-turtles-beam.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.changeset/hungry-turtles-beam.md b/.changeset/hungry-turtles-beam.md index dfe9942c5c8e..6eb60a9faaa9 100644 --- a/.changeset/hungry-turtles-beam.md +++ b/.changeset/hungry-turtles-beam.md @@ -2,4 +2,16 @@ "wrangler": patch --- -Add support for custom instance types for users without the `REQUIRE_INSTANCE_TYPE` capability +Add support for custom instance limits for containers. For example, instead of +having to use the preconfigured dev/standard/basic instance types, you can now +set: + +``` +instance_type: { + vcpu: 1, + memory_mib: 1024, + disk_mb: 4000 +} +``` + +This feature is currently only available to customers on an enterprise plan. From 08414c1888f119653519cea860850caf3515c60e Mon Sep 17 00:00:00 2001 From: Nikita Sharma Date: Wed, 30 Jul 2025 09:25:58 -0500 Subject: [PATCH 8/9] add config tests for normalization of custom instance types --- .../src/__tests__/containers/config.test.ts | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/packages/wrangler/src/__tests__/containers/config.test.ts b/packages/wrangler/src/__tests__/containers/config.test.ts index 1d67615f2926..1c14a91c948d 100644 --- a/packages/wrangler/src/__tests__/containers/config.test.ts +++ b/packages/wrangler/src/__tests__/containers/config.test.ts @@ -196,6 +196,7 @@ describe("getNormalizedContainerOptions", () => { }); it("should handle custom limit configuration", async () => { + // deprecated path for setting custom limits const config: Config = { name: "test-worker", configPath: "/test/wrangler.toml", @@ -240,6 +241,95 @@ describe("getNormalizedContainerOptions", () => { }); }); + it("should handle custom limit configuration through instance_type", async () => { + // updated path for setting custom limits + const config: Config = { + name: "test-worker", + configPath: "/test/wrangler.toml", + userConfigPath: "/test/wrangler.toml", + topLevelName: "test-worker", + containers: [ + { + name: "test-container", + class_name: "TestContainer", + image: "registry.example.com/test:latest", + instance_type: { + disk_mb: 5000, + memory_mib: 1024, + vcpu: 2, + }, + }, + ], + durable_objects: { + bindings: [ + { + name: "TEST_DO", + class_name: "TestContainer", + }, + ], + }, + } as Partial as Config; + + const result = await getNormalizedContainerOptions(config); + expect(result).toHaveLength(1); + expect(result[0]).toMatchObject({ + name: "test-container", + class_name: "TestContainer", + max_instances: 0, + scheduling_policy: "default", + rollout_step_percentage: 25, + rollout_kind: "full_auto", + disk_bytes: 5_000_000_000, // 5000 MB in bytes + memory_mib: 1024, + vcpu: 2, + image_uri: "registry.example.com/test:latest", + constraints: { tier: 1 }, + }); + }); + + it("should normalize and set defaults for custom limits to dev instance type", async () => { + const config: Config = { + name: "test-worker", + configPath: "/test/wrangler.toml", + userConfigPath: "/test/wrangler.toml", + topLevelName: "test-worker", + containers: [ + { + name: "test-container", + class_name: "TestContainer", + image: "registry.example.com/test:latest", + instance_type: { + vcpu: 2, + }, + }, + ], + durable_objects: { + bindings: [ + { + name: "TEST_DO", + class_name: "TestContainer", + }, + ], + }, + } as Partial as Config; + + const result = await getNormalizedContainerOptions(config); + expect(result).toHaveLength(1); + expect(result[0]).toMatchObject({ + name: "test-container", + class_name: "TestContainer", + max_instances: 0, + scheduling_policy: "default", + rollout_step_percentage: 25, + rollout_kind: "full_auto", + disk_bytes: 2_000_000_000, // 2000 MB in bytes + memory_mib: 256, + vcpu: 2, + image_uri: "registry.example.com/test:latest", + constraints: { tier: 1 }, + }); + }); + it("should handle instance type configuration", async () => { const config: Config = { name: "test-worker", From f9b34ed461f530b090b092fd2768b3b08f9c04d3 Mon Sep 17 00:00:00 2001 From: Nikita Sharma Date: Wed, 30 Jul 2025 09:33:46 -0500 Subject: [PATCH 9/9] update jsdoc comments --- packages/wrangler/src/config/environment.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/wrangler/src/config/environment.ts b/packages/wrangler/src/config/environment.ts index 0bb24d198f11..19adce58c764 100644 --- a/packages/wrangler/src/config/environment.ts +++ b/packages/wrangler/src/config/environment.ts @@ -97,9 +97,13 @@ export type ContainerApp = { /** * The instance type to be used for the container. - * dev = 1/16 vCPU, 256 MiB memory, and 2 GB disk - * basic = 1/4 vCPU, 1 GiB memory, and 4 GB disk - * standard = 1/2 vCPU, 4 GiB memory, and 4 GB disk + * Select from one of the following named instance types: + * - dev: 1/16 vCPU, 256 MiB memory, and 2 GB disk + * - basic: 1/4 vCPU, 1 GiB memory, and 4 GB disk + * - standard: 1/2 vCPU, 4 GiB memory, and 4 GB disk + * + * Customers on an enterprise plan have the additional option to set custom limits. + * * @optional * @default "dev" */ @@ -108,8 +112,13 @@ export type ContainerApp = { | "basic" | "standard" | { + /** @defaults to 0.0625 (1/16 vCPU) */ vcpu?: number; + + /** @defaults to 256 MiB */ memory_mib?: number; + + /** @defaults to 2 GB */ disk_mb?: number; };