Skip to main content

@daemon

Makes method callable via Redux action.

Signatures

// Default mode (Sync)
@daemon()
*method() { }

// Specific mode
@daemon(mode: DaemonMode)
*method() { }

// Mode with custom action pattern
@daemon(mode: DaemonMode, action: Pattern<any>)
*method() { }

// Schedule mode with interval
@daemon(DaemonMode.Schedule, intervalMs: number)
*method() { }

DaemonMode

enum DaemonMode {
Sync = 'SYNC', // Block until previous completes
Every = 'EVERY', // Run all in parallel (takeEvery)
Last = 'LAST', // Cancel previous (takeLatest)
Schedule = 'SCHEDULE' // Run periodically
}
ModeBehaviorUse Case
SyncWait for previous call to completeForm submissions, navigation
EveryRun all calls in parallelAnalytics, logging
LastCancel previous, run latestSearch, autocomplete
ScheduleRun periodicallyPolling, heartbeat

Basic Usage

class FormService extends Service {
toString() { return 'FormService'; }

// Sync mode (default) - wait for previous to complete
@daemon()
*submitForm(data: FormData) {
return yield* call(api.submit, data);
}
}

DaemonMode.Last

Cancel previous call when new one arrives (like takeLatest):

class SearchService extends Service {
toString() { return 'SearchService'; }

@daemon(DaemonMode.Last)
*search(query: string) {
yield* delay(300); // Debounce
return yield* call(api.search, query);
}
}

DaemonMode.Every

Run all calls in parallel (like takeEvery):

class AnalyticsService extends Service {
toString() { return 'AnalyticsService'; }

@daemon(DaemonMode.Every)
*trackEvent(event: string, data: object) {
yield* call(analytics.track, event, data);
}
}

DaemonMode.Schedule

Run periodically:

class NotificationService extends Service {
toString() { return 'NotificationService'; }

@daemon(DaemonMode.Schedule, 10000) // Every 10 seconds
*pollNotifications() {
return yield* call(api.getNotifications);
}
}

Custom Action Pattern

Listen to external Redux actions:

class RouterService extends Service {
toString() { return 'RouterService'; }

@daemon(DaemonMode.Every, 'LOCATION_CHANGE')
*onRouteChange(action: LocationChangeAction) {
yield* call(this.handleNavigation, action.payload);
}
}

Calling Daemon Methods

Use useServiceConsumer to get bound actions:

function SearchForm() {
const { actions } = useServiceConsumer(SearchService);

return (
<input
onChange={(e) => actions.search(e.target.value)}
placeholder="Search..."
/>
);
}

Combining with @operation

class UserService extends Service {
toString() { return 'UserService'; }

@operation // Save result to store
@daemon() // Make callable via action
*fetchUser(id: string) {
return yield* call(api.getUser, id);
}
}

See Also