@@ -7,6 +7,9 @@ package io.airbyte.workload.services
77import io.airbyte.commons.enums.convertTo
88import io.airbyte.config.WorkloadPriority
99import io.airbyte.config.WorkloadType
10+ import io.airbyte.featureflag.Empty
11+ import io.airbyte.featureflag.FeatureFlagClient
12+ import io.airbyte.featureflag.UseAtomicWorkloadStateTransitions
1013import io.airbyte.workload.common.DefaultDeadlineValues
1114import io.airbyte.workload.repository.WorkloadQueueRepository
1215import io.airbyte.workload.repository.WorkloadRepository
@@ -43,6 +46,7 @@ class WorkloadService(
4346 private val workloadQueueRepository : WorkloadQueueRepository ,
4447 private val signalSender : SignalSender ,
4548 private val defaultDeadlineValues : DefaultDeadlineValues ,
49+ private val featureFlagClient : FeatureFlagClient ,
4650) {
4751 fun createWorkload (
4852 workloadId : String ,
@@ -113,25 +117,49 @@ class WorkloadService(
113117 source : String? ,
114118 reason : String? ,
115119 ) {
116- val workload = getWorkload(workloadId)
117-
118- when (workload.status) {
119- WorkloadStatus .PENDING , WorkloadStatus .LAUNCHED , WorkloadStatus .CLAIMED , WorkloadStatus .RUNNING -> {
120- workloadRepository.update(
121- workloadId,
122- WorkloadStatus .CANCELLED ,
123- source,
124- reason,
125- null ,
126- )
120+ if (featureFlagClient.boolVariation(UseAtomicWorkloadStateTransitions , Empty )) {
121+ val workload = workloadRepository.cancel(workloadId, reason = reason, source = source)
122+ if (workload != null ) {
123+ workloadQueueRepository.ackWorkloadQueueItem(workloadId)
127124 signalSender.sendSignal(workload.type, workload.signalInput)
125+ } else {
126+ workloadRepository
127+ .findById(workloadId)
128+ .map { w ->
129+ when (w.status) {
130+ WorkloadStatus .FAILURE , WorkloadStatus .SUCCESS -> throw InvalidStatusTransitionException (
131+ " Cannot cancel a workload in either success or failure status. Workload id: $workloadId has status: ${w.status} " ,
132+ )
133+ WorkloadStatus .CANCELLED ->
134+ logger.info {
135+ " Workload $workloadId is already cancelled. Cancelling an already cancelled workload is a noop"
136+ }
137+ else -> logger.error { " Cancelling workload $workloadId failed to update its status, status is ${w.status} " }
138+ }
139+ }
140+ }
141+ } else {
142+ val workload = getWorkload(workloadId)
128143
129- workloadQueueRepository.ackWorkloadQueueItem(workloadId)
144+ when (workload.status) {
145+ WorkloadStatus .PENDING , WorkloadStatus .LAUNCHED , WorkloadStatus .CLAIMED , WorkloadStatus .RUNNING -> {
146+ workloadRepository.update(
147+ workloadId,
148+ WorkloadStatus .CANCELLED ,
149+ source,
150+ reason,
151+ null ,
152+ )
153+ signalSender.sendSignal(workload.type, workload.signalInput)
154+
155+ workloadQueueRepository.ackWorkloadQueueItem(workloadId)
156+ }
157+
158+ WorkloadStatus .CANCELLED -> logger.info { " Workload $workloadId is already cancelled. Cancelling an already cancelled workload is a noop" }
159+ else -> throw InvalidStatusTransitionException (
160+ " Cannot cancel a workload in either success or failure status. Workload id: $workloadId has status: ${workload.status} " ,
161+ )
130162 }
131- WorkloadStatus .CANCELLED -> logger.info { " Workload $workloadId is already cancelled. Cancelling an already cancelled workload is a noop" }
132- else -> throw InvalidStatusTransitionException (
133- " Cannot cancel a workload in either success or failure status. Workload id: $workloadId has status: ${workload.status} " ,
134- )
135163 }
136164 }
137165
@@ -140,25 +168,95 @@ class WorkloadService(
140168 source : String? ,
141169 reason : String? ,
142170 ) {
143- val workload = getWorkload(workloadId)
144- when (workload.status) {
145- WorkloadStatus .PENDING , WorkloadStatus .CLAIMED , WorkloadStatus .LAUNCHED , WorkloadStatus .RUNNING -> {
146- workloadRepository.update(
147- workloadId,
148- WorkloadStatus .FAILURE ,
149- source,
150- reason,
151- null ,
152- )
171+ if (featureFlagClient.boolVariation(UseAtomicWorkloadStateTransitions , Empty )) {
172+ val workload = workloadRepository.fail(workloadId, reason = reason, source = source)
173+ if (workload != null ) {
174+ workloadQueueRepository.ackWorkloadQueueItem(workloadId)
153175 signalSender.sendSignal(workload.type, workload.signalInput)
176+ } else {
177+ workloadRepository
178+ .findById(workloadId)
179+ .map { w ->
180+ when (w.status) {
181+ WorkloadStatus .CANCELLED , WorkloadStatus .SUCCESS -> throw InvalidStatusTransitionException (
182+ " Cannot fail a workload in either canceled or success status. Workload id: $workloadId has status: ${w.status} " ,
183+ )
184+ WorkloadStatus .FAILURE ->
185+ logger.info {
186+ " Workload $workloadId is already failed. Failing an already failed workload is a noop"
187+ }
188+ else -> logger.error { " Failed workload $workloadId failed to update its status, status is ${w.status} " }
189+ }
190+ }
191+ }
192+ } else {
193+ val workload = getWorkload(workloadId)
194+ when (workload.status) {
195+ WorkloadStatus .PENDING , WorkloadStatus .CLAIMED , WorkloadStatus .LAUNCHED , WorkloadStatus .RUNNING -> {
196+ workloadRepository.update(
197+ workloadId,
198+ WorkloadStatus .FAILURE ,
199+ source,
200+ reason,
201+ null ,
202+ )
203+ signalSender.sendSignal(workload.type, workload.signalInput)
204+
205+ workloadQueueRepository.ackWorkloadQueueItem(workloadId)
206+ }
154207
208+ WorkloadStatus .FAILURE -> logger.info { " Workload $workloadId is already marked as failed. Failing an already failed workload is a noop" }
209+ else -> throw InvalidStatusTransitionException (
210+ " Tried to fail a workload that is not active. Workload id: $workloadId has status: ${workload.status} " ,
211+ )
212+ }
213+ }
214+ }
215+
216+ fun succeedWorkload (workloadId : String ) {
217+ if (featureFlagClient.boolVariation(UseAtomicWorkloadStateTransitions , Empty )) {
218+ val workload = workloadRepository.succeed(workloadId)
219+ if (workload != null ) {
155220 workloadQueueRepository.ackWorkloadQueueItem(workloadId)
221+ signalSender.sendSignal(workload.type, workload.signalInput)
222+ } else {
223+ workloadRepository
224+ .findById(workloadId)
225+ .map { w ->
226+ when (w.status) {
227+ WorkloadStatus .CANCELLED , WorkloadStatus .FAILURE -> throw InvalidStatusTransitionException (
228+ " Cannot fail a workload in either canceled or failure status. Workload id: $workloadId has status: ${w.status} " ,
229+ )
230+
231+ WorkloadStatus .SUCCESS ->
232+ logger.info {
233+ " Workload $workloadId is already successful. Succeeding an already successful workload is a noop"
234+ }
235+
236+ else -> logger.error { " Failed workload $workloadId failed to update its status, status is ${w.status} " }
237+ }
238+ }
156239 }
240+ } else {
241+ val workload = getWorkload(workloadId)
157242
158- WorkloadStatus .FAILURE -> logger.info { " Workload $workloadId is already marked as failed. Failing an already failed workload is a noop" }
159- else -> throw InvalidStatusTransitionException (
160- " Tried to fail a workload that is not active. Workload id: $workloadId has status: ${workload.status} " ,
161- )
243+ when (workload.status) {
244+ WorkloadStatus .CLAIMED , WorkloadStatus .LAUNCHED , WorkloadStatus .RUNNING -> {
245+ workloadRepository.update(
246+ workloadId,
247+ WorkloadStatus .SUCCESS ,
248+ null ,
249+ )
250+ signalSender.sendSignal(workload.type, workload.signalInput)
251+ }
252+
253+ WorkloadStatus .SUCCESS ->
254+ logger.info { " Workload $workloadId is already marked as succeeded. Succeeding an already succeeded workload is a noop" }
255+
256+ else -> throw InvalidStatusTransitionException (
257+ " Tried to succeed a workload that is not active. Workload id: $workloadId has status: ${workload.status} " ,
258+ )
259+ }
162260 }
163261 }
164262
0 commit comments