[GH-ISSUE #279] Add deployment cancellation feature #183

Open
opened 2026-03-03 11:13:37 +03:00 by kerem · 2 comments
Owner

Originally created by @pavanbhaskardev on GitHub (Jun 30, 2025).
Original GitHub issue: https://github.com/dflow-sh/dflow/issues/279

Originally assigned to: @pavanbhaskardev on GitHub.

  1. Each deployment should have cancel button which will cancel the deployment
Originally created by @pavanbhaskardev on GitHub (Jun 30, 2025). Original GitHub issue: https://github.com/dflow-sh/dflow/issues/279 Originally assigned to: @pavanbhaskardev on GitHub. 1. Each deployment should have cancel button which will cancel the deployment
Author
Owner

@pavanbhaskardev commented on GitHub (Jul 18, 2025):

  1. tried removing a job from queue with queue-id, we can't cancel a queue which is active https://github.com/taskforcesh/bullmq/issues/632
const QUEUE_NAME = `server-scale-app`

    const testQueue = getQueue({
      name: QUEUE_NAME,
      connection: queueConnection,
    })

    const removeResponse = await testQueue.remove(jobId)
<!-- gh-comment-id:3089381297 --> @pavanbhaskardev commented on GitHub (Jul 18, 2025): 1. tried removing a job from queue with queue-id, we can't cancel a queue which is active https://github.com/taskforcesh/bullmq/issues/632 ``` const QUEUE_NAME = `server-scale-app` const testQueue = getQueue({ name: QUEUE_NAME, connection: queueConnection, }) const removeResponse = await testQueue.remove(jobId) ```
Author
Owner

@pavanbhaskardev commented on GitHub (Jul 22, 2025):

  1. Tried a another approach where we'll fetch redis-flag after every-step. we'll throw new Error("deployment-cancelled") error when redis-flag is true, here is example
// testQueue.ts
import { getQueue, getWorker } from '@/lib/bullmq'
import { queueConnection } from '@/lib/redis'
import { sleep } from '@/lib/sleep'

// this method will fetch the redis-flag `cancel-deployment:${deploymentId}` after every-step and throw an error
async function isCancelled(deploymentId: string) {
  const cancel = await queueConnection.get(`cancel-deployment:${deploymentId}`)

  if (cancel === 'true') {
    throw new Error('Deployment Cancelled')
  }
}

export const addTestQueue = async () => {
  const QUEUE_NAME = `server-scale-app`

  const testQueue = getQueue({
    name: QUEUE_NAME,
    connection: queueConnection,
  })

  const worker = getWorker({
    name: QUEUE_NAME,
    processor: async job => {
      console.log("i'm started")

      await sleep(2000)
      console.log('Job 1: done')
      await isCancelled(job.id ?? '')

      await sleep(10000)
      console.log('Job 2: done')
      await isCancelled(job.id ?? '')

      await sleep(20000)
      console.log('Job 3: done')
      await isCancelled(job.id ?? '')
    },
    connection: queueConnection,
  })

  worker.on('failed', () => {
    console.log('test-queue closed')
  })

  // we need to store the id in deployments collection so that we can use that during cancellation process
  const id = `test:${new Date().getTime()}`

  return await testQueue.add(id, undefined, {
    jobId: id,
  })
}

// actions/service/index.ts
export const cancelQueue = protectedClient
  .metadata({
    actionName: 'cancelQueue',
  })
  .schema(
    z.object({
      jobId: z.string(),
    }),
  )
  .action(async ({ clientInput }) => {
    const { jobId } = clientInput

    // here we're setting flag to true
    const setResponse = await queueConnection.set(
      `cancel-deployment:${jobId}`,
      'true',
    )
    return setResponse
  })
<!-- gh-comment-id:3101921082 --> @pavanbhaskardev commented on GitHub (Jul 22, 2025): 1. Tried a another approach where we'll fetch `redis-flag` after every-step. we'll `throw new Error("deployment-cancelled")` error when `redis-flag` is true, here is example ```ts // testQueue.ts import { getQueue, getWorker } from '@/lib/bullmq' import { queueConnection } from '@/lib/redis' import { sleep } from '@/lib/sleep' // this method will fetch the redis-flag `cancel-deployment:${deploymentId}` after every-step and throw an error async function isCancelled(deploymentId: string) { const cancel = await queueConnection.get(`cancel-deployment:${deploymentId}`) if (cancel === 'true') { throw new Error('Deployment Cancelled') } } export const addTestQueue = async () => { const QUEUE_NAME = `server-scale-app` const testQueue = getQueue({ name: QUEUE_NAME, connection: queueConnection, }) const worker = getWorker({ name: QUEUE_NAME, processor: async job => { console.log("i'm started") await sleep(2000) console.log('Job 1: done') await isCancelled(job.id ?? '') await sleep(10000) console.log('Job 2: done') await isCancelled(job.id ?? '') await sleep(20000) console.log('Job 3: done') await isCancelled(job.id ?? '') }, connection: queueConnection, }) worker.on('failed', () => { console.log('test-queue closed') }) // we need to store the id in deployments collection so that we can use that during cancellation process const id = `test:${new Date().getTime()}` return await testQueue.add(id, undefined, { jobId: id, }) } ``` ```ts // actions/service/index.ts export const cancelQueue = protectedClient .metadata({ actionName: 'cancelQueue', }) .schema( z.object({ jobId: z.string(), }), ) .action(async ({ clientInput }) => { const { jobId } = clientInput // here we're setting flag to true const setResponse = await queueConnection.set( `cancel-deployment:${jobId}`, 'true', ) return setResponse }) ```
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/dflow#183
No description provided.