Skip to content

Commit 0f8d69d

Browse files
containers: users can set multiple tiers for constraints (#11755)
* allow specifying tiers in application constraints * changeset * pr feedback * changeset
1 parent a50c01d commit 0f8d69d

9 files changed

Lines changed: 205 additions & 44 deletions

File tree

.changeset/wide-suns-brush.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"@cloudflare/containers-shared": patch
3+
"@cloudflare/workers-utils": minor
4+
"wrangler": minor
5+
---
6+
7+
Users can now specify `constraints.tiers` for their container applications. `tier` is deprecated in favor of `tiers`.
8+
If left unset, we will default to `tiers: [1, 2]`.
9+
Note that `constraints` is an experimental feature.

packages/containers-shared/src/client/models/ApplicationConstraints.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type { Region } from "./Region";
99
export type ApplicationConstraints = {
1010
region?: Region;
1111
tier?: number;
12+
tiers?: Array<number>;
1213
regions?: Array<Region>;
1314
cities?: Array<City>;
1415
pops?: Array<ApplicationConstraintPop>;

packages/containers-shared/src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export type SharedContainerConfig = {
8484
constraints: {
8585
regions?: string[];
8686
cities?: string[];
87-
tier: number | undefined;
87+
tiers?: number[];
8888
};
8989
affinities?: {
9090
colocation?: ApplicationAffinityColocation;

packages/workers-utils/src/config/environment.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,11 @@ export type ContainerApp = {
219219
constraints?: {
220220
regions?: string[];
221221
cities?: string[];
222+
/**
223+
* @deprecated Use `tiers` instead
224+
*/
222225
tier?: number;
226+
tiers?: number[];
223227
};
224228

225229
/**

packages/workers-utils/src/config/validation.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3180,6 +3180,36 @@ function validateContainerApp(
31803180
}
31813181
}
31823182

3183+
if (
3184+
validateOptionalProperty(
3185+
diagnostics,
3186+
field,
3187+
"constraints",
3188+
containerAppOptional.constraints,
3189+
"object"
3190+
) &&
3191+
containerAppOptional.constraints
3192+
) {
3193+
const constraints = containerAppOptional.constraints;
3194+
if ("tier" in constraints) {
3195+
diagnostics.warnings.push(
3196+
`"constraints.tier" has been deprecated in favor of "constraints.tiers". Please update your configuration to use "constraints.tiers" instead.`
3197+
);
3198+
3199+
if ("tiers" in constraints) {
3200+
diagnostics.errors.push(
3201+
`${field}.constraints.tier and ${field}.constraints.tiers cannot both be set`
3202+
);
3203+
}
3204+
}
3205+
validateOptionalTypedArray(
3206+
diagnostics,
3207+
`${field}.constraints.tiers`,
3208+
constraints.tiers,
3209+
"number"
3210+
);
3211+
}
3212+
31833213
// Instance Type validation: When present, the instance type should be either (1) a string
31843214
// representing a predefined instance type or (2) an object that optionally defines vcpu,
31853215
// memory, and disk.

packages/workers-utils/tests/config/validation/normalize-and-validate-config.test.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2789,6 +2789,86 @@ describe("normalizeAndValidateConfig()", () => {
27892789
- The \\"dev\\" instance_type has been renamed to \\"lite\\" and will be removed in a subsequent version. Please update your configuration to use \\"lite\\" instead."
27902790
`);
27912791
});
2792+
2793+
it("should error when both constraints.tier and constraints.tiers are set", () => {
2794+
const { diagnostics } = normalizeAndValidateConfig(
2795+
{
2796+
name: "test-worker",
2797+
containers: [
2798+
{
2799+
class_name: "TestClass",
2800+
image: "registry.cloudflare.com/test:latest",
2801+
constraints: {
2802+
tier: 1,
2803+
tiers: [1, 2],
2804+
},
2805+
},
2806+
],
2807+
} as unknown as RawConfig,
2808+
undefined,
2809+
undefined,
2810+
{ env: undefined }
2811+
);
2812+
2813+
expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
2814+
"Processing wrangler configuration:
2815+
- \\"constraints.tier\\" has been deprecated in favor of \\"constraints.tiers\\". Please update your configuration to use \\"constraints.tiers\\" instead."
2816+
`);
2817+
expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
2818+
"Processing wrangler configuration:
2819+
- containers.constraints.tier and containers.constraints.tiers cannot both be set"
2820+
`);
2821+
});
2822+
2823+
it("should error when constraints.tiers is not an array of numbers", () => {
2824+
const { diagnostics } = normalizeAndValidateConfig(
2825+
{
2826+
name: "test-worker",
2827+
containers: [
2828+
{
2829+
class_name: "TestClass",
2830+
image: "registry.cloudflare.com/test:latest",
2831+
constraints: {
2832+
tiers: ["a", "b"],
2833+
},
2834+
},
2835+
],
2836+
} as unknown as RawConfig,
2837+
undefined,
2838+
undefined,
2839+
{ env: undefined }
2840+
);
2841+
2842+
expect(diagnostics.hasWarnings()).toBe(false);
2843+
expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
2844+
"Processing wrangler configuration:
2845+
- Expected \\"containers.constraints.tiers.[0]\\" to be of type number but got \\"a\\".
2846+
- Expected \\"containers.constraints.tiers.[1]\\" to be of type number but got \\"b\\"."
2847+
`);
2848+
});
2849+
2850+
it("should allow valid constraints.tiers array of numbers", () => {
2851+
const { diagnostics } = normalizeAndValidateConfig(
2852+
{
2853+
name: "test-worker",
2854+
containers: [
2855+
{
2856+
class_name: "TestClass",
2857+
image: "registry.cloudflare.com/test:latest",
2858+
constraints: {
2859+
tiers: [1, 2, 3],
2860+
},
2861+
},
2862+
],
2863+
} as unknown as RawConfig,
2864+
undefined,
2865+
undefined,
2866+
{ env: undefined }
2867+
);
2868+
2869+
expect(diagnostics.hasWarnings()).toBe(false);
2870+
expect(diagnostics.hasErrors()).toBe(false);
2871+
});
27922872
});
27932873

27942874
describe("[kv_namespaces]", () => {

packages/wrangler/src/__tests__/containers/config.test.ts

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ describe("getNormalizedContainerOptions", () => {
150150
dockerfile: expect.stringMatching(/[/\\]Dockerfile$/),
151151
image_build_context: expect.stringMatching(/[/\\][^/\\]*$/),
152152
image_vars: undefined,
153-
constraints: { tier: 1 },
153+
constraints: { tiers: [1, 2] },
154154
observability: {
155155
logs_enabled: false,
156156
},
@@ -193,7 +193,7 @@ describe("getNormalizedContainerOptions", () => {
193193
rollout_kind: "full_auto",
194194
instance_type: "lite",
195195
image_uri: "registry.cloudflare.com/some-account-id/test:latest",
196-
constraints: { tier: 1 },
196+
constraints: { tiers: [1, 2] },
197197
observability: {
198198
logs_enabled: false,
199199
},
@@ -280,7 +280,7 @@ describe("getNormalizedContainerOptions", () => {
280280
memory_mib: 1024,
281281
vcpu: 2,
282282
image_uri: "registry.cloudflare.com/some-account-id/test:latest",
283-
constraints: { tier: 1 },
283+
constraints: { tiers: [1, 2] },
284284
});
285285
});
286286

@@ -328,7 +328,7 @@ describe("getNormalizedContainerOptions", () => {
328328
memory_mib: 1024,
329329
vcpu: 2,
330330
image_uri: "registry.cloudflare.com/some-account-id/test:latest",
331-
constraints: { tier: 1 },
331+
constraints: { tiers: [1, 2] },
332332
});
333333
});
334334

@@ -373,7 +373,7 @@ describe("getNormalizedContainerOptions", () => {
373373
memory_mib: 256,
374374
vcpu: 2,
375375
image_uri: "registry.cloudflare.com/some-account-id/test:latest",
376-
constraints: { tier: 1 },
376+
constraints: { tiers: [1, 2] },
377377
});
378378
});
379379

@@ -414,7 +414,7 @@ describe("getNormalizedContainerOptions", () => {
414414
rollout_kind: "full_auto",
415415
instance_type: "standard",
416416
image_uri: "registry.cloudflare.com/some-account-id/test:latest",
417-
constraints: { tier: 1 },
417+
constraints: { tiers: [1, 2] },
418418
});
419419
});
420420

@@ -472,7 +472,7 @@ describe("getNormalizedContainerOptions", () => {
472472
instance_type: "basic",
473473
image_uri: "registry.cloudflare.com/some-account-id/test:latest",
474474
constraints: {
475-
tier: 2,
475+
tiers: [2],
476476
regions: ["US-EAST-1", "US-WEST-2"],
477477
cities: ["nyc", "sf"],
478478
},
@@ -525,7 +525,7 @@ describe("getNormalizedContainerOptions", () => {
525525
dockerfile: expect.stringMatching(/[/\\]nested[/\\]Dockerfile$/),
526526
image_build_context: expect.stringMatching(/[/\\]nested$/),
527527
image_vars: undefined,
528-
constraints: { tier: 1 },
528+
constraints: { tiers: [1, 2] },
529529
observability: {
530530
logs_enabled: false,
531531
},
@@ -634,7 +634,36 @@ describe("getNormalizedContainerOptions", () => {
634634

635635
const result = await getNormalizedContainerOptions(config, {});
636636
expect(result).toHaveLength(1);
637-
expect(result[0].constraints.tier).toBeUndefined();
637+
expect(result[0].constraints.tiers).toBeUndefined();
638+
});
639+
640+
it("should convert deprecated tier to tiers array", async () => {
641+
const config: Config = {
642+
name: "test-worker",
643+
containers: [
644+
{
645+
class_name: "TestContainer",
646+
image: `${getCloudflareContainerRegistry()}/test:latest`,
647+
name: "test-container",
648+
constraints: {
649+
tier: 3,
650+
},
651+
},
652+
],
653+
durable_objects: {
654+
bindings: [
655+
{
656+
name: "TEST_DO",
657+
class_name: "TestContainer",
658+
},
659+
],
660+
},
661+
migrations: [{ tag: "v1", new_sqlite_classes: ["TestContainer"] }],
662+
} as Partial<Config> as Config;
663+
664+
const result = await getNormalizedContainerOptions(config, {});
665+
expect(result).toHaveLength(1);
666+
expect(result[0].constraints.tiers).toEqual([3]);
638667
});
639668

640669
it("should default rollout_step_percentage to 100 when max_instances is 1", async () => {

0 commit comments

Comments
 (0)