44 type WorkloadManagerCreateOptions ,
55 type WorkloadManagerOptions ,
66} from "./types.js" ;
7- import type { EnvironmentType , MachinePreset } from "@trigger.dev/core/v3" ;
7+ import type { EnvironmentType , MachinePreset , PlacementTag } from "@trigger.dev/core/v3" ;
88import { env } from "../env.js" ;
99import { type K8sApi , createK8sApi , type k8s } from "../clients/kubernetes.js" ;
1010import { getRunnerId } from "../util.js" ;
@@ -13,22 +13,20 @@ type ResourceQuantities = {
1313 [ K in "cpu" | "memory" | "ephemeral-storage" ] ?: string ;
1414} ;
1515
16- interface TierConfig {
16+ interface PlacementConfig {
1717 enabled : boolean ;
18- labelKey : string ;
19- freeValue : string ;
20- paidValue : string ;
18+ prefix : string ;
2119}
2220
2321export class KubernetesWorkloadManager implements WorkloadManager {
2422 private readonly logger = new SimpleStructuredLogger ( "kubernetes-workload-provider" ) ;
2523 private k8s : K8sApi ;
2624 private namespace = env . KUBERNETES_NAMESPACE ;
27- private tierConfig : TierConfig ;
25+ private placementConfig : PlacementConfig ;
2826
2927 constructor ( private opts : WorkloadManagerOptions ) {
3028 this . k8s = createK8sApi ( ) ;
31- this . tierConfig = this . tierSchedulingConfig ;
29+ this . placementConfig = this . placementTagsConfig ;
3230
3331 if ( opts . workloadApiDomain ) {
3432 this . logger . warn ( "[KubernetesWorkloadManager] ⚠️ Custom workload API domain" , {
@@ -37,34 +35,56 @@ export class KubernetesWorkloadManager implements WorkloadManager {
3735 }
3836 }
3937
40- private get tierSchedulingConfig ( ) : TierConfig {
38+ private get placementTagsConfig ( ) : PlacementConfig {
4139 return {
42- enabled : env . ENABLE_TIER_SCHEDULING ,
43- labelKey : env . TIER_LABEL_KEY ,
44- freeValue : env . TIER_LABEL_VALUE_FREE ,
45- paidValue : env . TIER_LABEL_VALUE_PAID ,
40+ enabled : env . PLACEMENT_TAGS_ENABLED ,
41+ prefix : env . PLACEMENT_TAGS_PREFIX ,
4642 } ;
4743 }
4844
49- private addTierScheduling (
45+ private addPlacementTags (
5046 podSpec : Omit < k8s . V1PodSpec , "containers" > ,
51- isPaidTier : boolean
47+ placementTags ?: PlacementTag [ ]
5248 ) : Omit < k8s . V1PodSpec , "containers" > {
53- if ( ! this . tierConfig . enabled ) {
49+ if ( ! this . placementConfig . enabled || ! placementTags || placementTags . length === 0 ) {
5450 return podSpec ;
5551 }
5652
57- const labelValue = isPaidTier ? this . tierConfig . paidValue : this . tierConfig . freeValue ;
53+ const nodeSelector : Record < string , string > = { ...podSpec . nodeSelector } ;
54+
55+ // Convert placement tags to nodeSelector labels
56+ for ( const tag of placementTags ) {
57+ const labelKey = `${ this . placementConfig . prefix } /${ tag . key } ` ;
58+
59+ // Print warnings (if any)
60+ this . printTagWarnings ( tag ) ;
61+
62+ // For now we only support single values via nodeSelector
63+ nodeSelector [ labelKey ] = tag . values ?. [ 0 ] ?? "" ;
64+ }
5865
5966 return {
6067 ...podSpec ,
61- nodeSelector : {
62- ...podSpec . nodeSelector ,
63- [ this . tierConfig . labelKey ] : labelValue ,
64- } ,
68+ nodeSelector,
6569 } ;
6670 }
6771
72+ private printTagWarnings ( tag : PlacementTag ) {
73+ if ( ! tag . values || tag . values . length === 0 ) {
74+ // No values provided
75+ this . logger . warn (
76+ "[KubernetesWorkloadManager] Placement tag has no values, using empty string" ,
77+ tag
78+ ) ;
79+ } else if ( tag . values . length > 1 ) {
80+ // Multiple values provided
81+ this . logger . warn (
82+ "[KubernetesWorkloadManager] Placement tag has multiple values, only using first one" ,
83+ tag
84+ ) ;
85+ }
86+ }
87+
6888 async create ( opts : WorkloadManagerCreateOptions ) {
6989 this . logger . log ( "[KubernetesWorkloadManager] Creating container" , { opts } ) ;
7090
@@ -85,7 +105,7 @@ export class KubernetesWorkloadManager implements WorkloadManager {
85105 } ,
86106 } ,
87107 spec : {
88- ...this . addTierScheduling ( this . #defaultPodSpec, opts . isPaidTier ?? false ) ,
108+ ...this . addPlacementTags ( this . #defaultPodSpec, opts . placementTags ) ,
89109 terminationGracePeriodSeconds : 60 * 60 ,
90110 containers : [
91111 {
0 commit comments