0
# Lifecycle Management
1
2
LoopBack Core provides comprehensive lifecycle management for coordinating application startup and shutdown sequences. The system ensures that all components, servers, and services are initialized, started, and stopped in the correct order with proper dependency management.
3
4
## Capabilities
5
6
### LifeCycleObserver Interface
7
8
Core interface for implementing lifecycle-aware components that need to participate in application startup and shutdown sequences.
9
10
```typescript { .api }
11
/**
12
* Observers to handle life cycle init/start/stop events
13
*/
14
interface LifeCycleObserver {
15
/** The method to be invoked during init. Called at most once per application instance. */
16
init?(...injectedArgs: unknown[]): ValueOrPromise<void>;
17
18
/** The method to be invoked during start */
19
start?(...injectedArgs: unknown[]): ValueOrPromise<void>;
20
21
/** The method to be invoked during stop */
22
stop?(...injectedArgs: unknown[]): ValueOrPromise<void>;
23
}
24
```
25
26
**Usage Examples:**
27
28
```typescript
29
import { LifeCycleObserver, inject } from "@loopback/core";
30
31
class DatabaseObserver implements LifeCycleObserver {
32
constructor(
33
@inject('datasources.db') private datasource: DataSource,
34
@inject('config.database') private config: DatabaseConfig
35
) {}
36
37
async init(): Promise<void> {
38
console.log('Initializing database connection...');
39
await this.datasource.connect();
40
}
41
42
async start(): Promise<void> {
43
console.log('Database connection ready');
44
await this.runMigrations();
45
}
46
47
async stop(): Promise<void> {
48
console.log('Closing database connection...');
49
await this.datasource.disconnect();
50
}
51
52
private async runMigrations(): Promise<void> {
53
if (this.config.autoMigrate) {
54
// Run database migrations
55
}
56
}
57
}
58
```
59
60
### Lifecycle Observer Decorator
61
62
Decorator for marking classes as lifecycle observers with optional group assignment and binding specifications.
63
64
```typescript { .api }
65
/**
66
* Sugar decorator to mark a class as life cycle observer
67
*/
68
function lifeCycleObserver(group?: string, ...specs: BindingSpec[]): ClassDecorator;
69
```
70
71
**Usage Examples:**
72
73
```typescript
74
import { lifeCycleObserver, LifeCycleObserver, BindingScope } from "@loopback/core";
75
76
// Basic lifecycle observer
77
@lifeCycleObserver()
78
class CacheObserver implements LifeCycleObserver {
79
async start(): Promise<void> {
80
console.log('Cache warming up...');
81
}
82
83
async stop(): Promise<void> {
84
console.log('Cache shutting down...');
85
}
86
}
87
88
// Observer with group assignment
89
@lifeCycleObserver('database')
90
class DatabaseObserver implements LifeCycleObserver {
91
async init(): Promise<void> {
92
console.log('Database initializing...');
93
}
94
}
95
96
// Observer with binding specifications
97
@lifeCycleObserver('server', {scope: BindingScope.SINGLETON})
98
class ServerObserver implements LifeCycleObserver {
99
async start(): Promise<void> {
100
console.log('Server starting...');
101
}
102
}
103
104
// Observer with multiple specifications
105
@lifeCycleObserver('external-services',
106
{scope: BindingScope.SINGLETON},
107
{tags: {priority: 'high'}}
108
)
109
class ExternalServiceObserver implements LifeCycleObserver {
110
async init(): Promise<void> {
111
console.log('Connecting to external services...');
112
}
113
}
114
```
115
116
### Lifecycle Utility Functions
117
118
Helper functions for working with lifecycle observers and bindings.
119
120
```typescript { .api }
121
/**
122
* Test if an object implements LifeCycleObserver
123
*/
124
function isLifeCycleObserver(obj: object): obj is LifeCycleObserver;
125
126
/**
127
* Test if a class implements LifeCycleObserver
128
*/
129
function isLifeCycleObserverClass(
130
ctor: Constructor<unknown>
131
): ctor is Constructor<LifeCycleObserver>;
132
133
/**
134
* A BindingTemplate function to configure the binding as life cycle observer
135
* by tagging it with CoreTags.LIFE_CYCLE_OBSERVER.
136
*/
137
function asLifeCycleObserver<T = unknown>(binding: Binding<T>): Binding<T>;
138
139
/**
140
* Find all life cycle observer bindings. By default, a binding tagged with
141
* CoreTags.LIFE_CYCLE_OBSERVER. Used as BindingFilter.
142
*/
143
const lifeCycleObserverFilter: BindingTagFilter;
144
```
145
146
**Usage Examples:**
147
148
```typescript
149
import {
150
isLifeCycleObserver,
151
isLifeCycleObserverClass,
152
asLifeCycleObserver,
153
lifeCycleObserverFilter,
154
LifeCycleObserver
155
} from "@loopback/core";
156
157
// Check if object implements lifecycle observer
158
const service = new MyService();
159
if (isLifeCycleObserver(service)) {
160
await service.start?.();
161
}
162
163
// Check if class implements lifecycle observer
164
class MyObserver implements LifeCycleObserver {
165
async start(): Promise<void> {}
166
}
167
168
if (isLifeCycleObserverClass(MyObserver)) {
169
console.log('MyObserver implements LifeCycleObserver');
170
}
171
172
// Configure binding as lifecycle observer
173
const binding = context.bind('my-observer')
174
.toClass(MyObserver)
175
.apply(asLifeCycleObserver);
176
177
// Find all lifecycle observer bindings
178
const observerBindings = context.find(lifeCycleObserverFilter);
179
```
180
181
### LifeCycleObserverRegistry
182
183
Central registry that manages and coordinates lifecycle observers with support for grouping, ordering, and parallel execution.
184
185
```typescript { .api }
186
/**
187
* A context-based registry for life cycle observers
188
*/
189
class LifeCycleObserverRegistry implements LifeCycleObserver {
190
constructor(
191
context: Context,
192
observersView: ContextView<LifeCycleObserver>,
193
options?: LifeCycleObserverOptions
194
);
195
196
/** Set the ordered groups for observer execution */
197
setOrderedGroups(groups: string[]): void;
198
199
/** Get observer groups ordered by the group configuration */
200
getObserverGroupsByOrder(): LifeCycleObserverGroup[];
201
202
/** Notify all life cycle observers by group of init */
203
init(): Promise<void>;
204
205
/** Notify all life cycle observers by group of start */
206
start(): Promise<void>;
207
208
/** Notify all life cycle observers by group of stop */
209
stop(): Promise<void>;
210
}
211
```
212
213
**Usage Examples:**
214
215
```typescript
216
import {
217
LifeCycleObserverRegistry,
218
LifeCycleObserverOptions,
219
DEFAULT_ORDERED_GROUPS
220
} from "@loopback/core";
221
222
// Custom registry configuration
223
const options: LifeCycleObserverOptions = {
224
orderedGroups: ['database', 'cache', 'server'],
225
disabledGroups: ['optional-services'],
226
parallel: true
227
};
228
229
// Manual registry usage (typically handled by Application)
230
const registry = new LifeCycleObserverRegistry(
231
context,
232
observersView,
233
options
234
);
235
236
// Set custom ordering
237
registry.setOrderedGroups(['datasource', 'server', 'monitoring']);
238
239
// Get ordered groups
240
const groups = registry.getObserverGroupsByOrder();
241
console.log('Observer groups:', groups.map(g => g.group));
242
243
// Manual lifecycle management
244
await registry.init();
245
await registry.start();
246
await registry.stop();
247
```
248
249
### Lifecycle Observer Options
250
251
Configuration interface for controlling how lifecycle observers are executed.
252
253
```typescript { .api }
254
interface LifeCycleObserverOptions {
255
/** Control the order of observer groups for notifications */
256
orderedGroups: string[];
257
258
/** Override and disable lifecycle observer groups */
259
disabledGroups?: string[];
260
261
/** Notify observers of the same group in parallel, default to true */
262
parallel?: boolean;
263
}
264
265
/** Default ordered groups configuration */
266
const DEFAULT_ORDERED_GROUPS: string[];
267
```
268
269
**Usage Examples:**
270
271
```typescript
272
import {
273
LifeCycleObserverOptions,
274
DEFAULT_ORDERED_GROUPS,
275
Application
276
} from "@loopback/core";
277
278
// Application with custom lifecycle options
279
const app = new Application();
280
281
// Configure lifecycle observer options
282
app.bind('lifeCycleObserver.options').to({
283
orderedGroups: ['database', 'cache', 'messaging', 'server'],
284
disabledGroups: ['debug-tools'],
285
parallel: true
286
} as LifeCycleObserverOptions);
287
288
// Use default groups (typically just ['server'])
289
console.log('Default groups:', DEFAULT_ORDERED_GROUPS);
290
291
// Sequential execution for critical services
292
const criticalOptions: LifeCycleObserverOptions = {
293
orderedGroups: ['database', 'auth', 'server'],
294
parallel: false // Execute sequentially within groups
295
};
296
```
297
298
### Lifecycle Observer Groups
299
300
Type definition for organizing lifecycle observers into logical groups with coordinated execution.
301
302
```typescript { .api }
303
/**
304
* A group of life cycle observers
305
*/
306
interface LifeCycleObserverGroup {
307
/** Observer group name */
308
group: string;
309
310
/** Bindings for observers within the group */
311
bindings: Readonly<Binding<LifeCycleObserver>>[];
312
}
313
```
314
315
**Usage Examples:**
316
317
```typescript
318
import { LifeCycleObserverGroup, lifeCycleObserver } from "@loopback/core";
319
320
// Observers in different groups
321
@lifeCycleObserver('database')
322
class DatabaseConnectionObserver implements LifeCycleObserver {
323
async init(): Promise<void> {
324
console.log('Database connection initializing...');
325
}
326
}
327
328
@lifeCycleObserver('database')
329
class DatabaseMigrationObserver implements LifeCycleObserver {
330
async start(): Promise<void> {
331
console.log('Running database migrations...');
332
}
333
}
334
335
@lifeCycleObserver('server')
336
class HttpServerObserver implements LifeCycleObserver {
337
async start(): Promise<void> {
338
console.log('HTTP server starting...');
339
}
340
}
341
342
// Groups will be organized as:
343
// {
344
// group: 'database',
345
// bindings: [DatabaseConnectionObserver, DatabaseMigrationObserver]
346
// }
347
// {
348
// group: 'server',
349
// bindings: [HttpServerObserver]
350
// }
351
```
352
353
### Application Lifecycle Integration
354
355
How lifecycle management integrates with the main Application class.
356
357
**Usage Examples:**
358
359
```typescript
360
import { Application, lifeCycleObserver, LifeCycleObserver } from "@loopback/core";
361
362
@lifeCycleObserver('cache')
363
class RedisObserver implements LifeCycleObserver {
364
async init(): Promise<void> {
365
console.log('Connecting to Redis...');
366
}
367
368
async start(): Promise<void> {
369
console.log('Redis cache ready');
370
}
371
372
async stop(): Promise<void> {
373
console.log('Disconnecting from Redis...');
374
}
375
}
376
377
@lifeCycleObserver('server')
378
class WebServerObserver implements LifeCycleObserver {
379
async start(): Promise<void> {
380
console.log('Web server listening...');
381
}
382
383
async stop(): Promise<void> {
384
console.log('Web server shut down');
385
}
386
}
387
388
const app = new Application();
389
390
// Register lifecycle observers
391
app.lifeCycleObserver(RedisObserver);
392
app.lifeCycleObserver(WebServerObserver);
393
394
// Application coordinates all observers
395
await app.start();
396
// Output:
397
// Connecting to Redis...
398
// Redis cache ready
399
// Web server listening...
400
401
await app.stop();
402
// Output:
403
// Web server shut down
404
// Disconnecting from Redis...
405
```
406
407
## Types
408
409
```typescript { .api }
410
type ValueOrPromise<T> = T | Promise<T>;
411
412
interface LifeCycleObserverGroup {
413
group: string;
414
bindings: Readonly<Binding<LifeCycleObserver>>[];
415
}
416
417
interface LifeCycleObserverOptions {
418
orderedGroups: string[];
419
disabledGroups?: string[];
420
parallel?: boolean;
421
}
422
423
const DEFAULT_ORDERED_GROUPS: string[];
424
```