Previous: TypeScript

Next: Advanced

Managing Task Concurrency

By default, ember-concurrency tasks run concurrently — if you call myTask.perform(); myTask.perform();, two instances of the task will run at the same time (unless the object they live on is destroyed, in which case they'll be canceled).

Often, you want to guarantee that no more than one instance of a task runs at the same time; for instance, if you have a task that saves model state to the server, you probably don't want that task to run concurrently — you want it to run sequentially, or you might want to ignore attempts to perform the task if it's already running. Manually enforcing these constraints is tricky and often results in redundant, error-prone boilerplate, but ember-concurrency makes it easy to rein in this undesired concurrency with the modifiers described below.


All of the examples below run the same task function (which just pauses for a moment and then completes), but with different task modifiers applied:

export default class SharedTasksController extends Controller {
  @task defaultTask = SHARED_TASK_FN;
  @task({ restartable: true }) restartableTask = SHARED_TASK_FN;
  @task({ enqueue: true }) enqueuedTask = SHARED_TASK_FN;
  @task({ drop: true }) droppingTask = SHARED_TASK_FN;
  @task({ keepLatest: true }) keepLatestTask = SHARED_TASK_FN;
Default Behavior: Tasks Run Concurrently

Tap the task.perform() button a few times. Note how the lifetimes of each task overlap, and each task runs to completion.


The restartable modifier ensures that only one instance of a task is running by canceling any currently-running tasks and starting a new task instance immediately. Note how there is no task overlap, and how currently running tasks get canceled if a new task starts before a prior one completes.

Check out Debounced Auto-Search for a practical example of restartable


The enqueue modifier ensures that only one instance of a task is running by maintaining a queue of pending tasks and running them sequentially. Note how there is no task overlap, but no tasks are canceled either.


The drop modifier drops tasks that are .perform()ed while another is already running. Dropped tasks' functions are never even called.

Check out the Loading UI example for a common use case for drop


The keepLatest will drop all but the most recent intermediate .perform(), which is enqueued to run later.

Use case: you poll the server in a loop, but during the server request, you get some other indication (say, via websockets) that the data is stale and you need to query the server again when the initial request completed.

Previous: TypeScript

Next: Advanced