Task Modifiers — restartable, drop, keepLatest

Pick a Concurrency Strategy

Task Modifiers — restartable, drop, keepLatest

Decorate a task to define how concurrent calls are handled — restart, drop, queue, or keep only the latest.

4 min read Level 3/5 #ember#concurrency#tasks
What you'll learn
  • Use restartable for type-ahead inputs
  • Use drop for double-submit guards
  • Use enqueue or keepLatest where appropriate

A task on its own runs every call to completion. The real power of ember-concurrency is concurrency modifiers — they tell the task what to do when called while a previous run is still in flight.

restartable

Cancel the running instance and start a fresh one. Perfect for type-ahead search:

import { task } from 'ember-concurrency';

searchTask = task({ restartable: true }, async (query) => {
  await timeout(300);            // debounce
  return this.store.query('post', { q: query });
});

Every keystroke restarts the task; only the last query actually fires.

drop

Ignore new perform calls while one is running. Great for save buttons:

saveTask = task({ drop: true }, async () => {
  await this.model.save();
});

Double-clicks don’t trigger duplicate saves.

enqueue

Queue new calls and run them one after another:

syncTask = task({ enqueue: true }, async (change) => {
  await this.api.push(change);
});

Useful when ordering matters and you can’t lose any calls.

keepLatest

Run the current one to completion, then run only the most-recent queued call, dropping any in between:

fetchTask = task({ keepLatest: true }, async () => {
  return this.api.fetch();
});

Good for polling or stale-while-revalidate patterns.

maxConcurrency

Combine with the strategies above to allow N parallel runs:

uploadTask = task({ enqueue: true, maxConcurrency: 3 }, async (file) => {
  return this.api.upload(file);
});

Up to three uploads run at once; the rest queue up.

The Router Service →