@navios/di 0.2.1 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +299 -38
- package/docs/README.md +121 -48
- package/docs/api-reference.md +763 -0
- package/docs/container.md +274 -0
- package/docs/examples/basic-usage.mts +97 -0
- package/docs/examples/factory-pattern.mts +318 -0
- package/docs/examples/injection-tokens.mts +225 -0
- package/docs/examples/request-scope-example.mts +254 -0
- package/docs/examples/service-lifecycle.mts +359 -0
- package/docs/factory.md +584 -0
- package/docs/getting-started.md +308 -0
- package/docs/injectable.md +496 -0
- package/docs/injection-tokens.md +400 -0
- package/docs/lifecycle.md +539 -0
- package/docs/scopes.md +749 -0
- package/lib/_tsup-dts-rollup.d.mts +494 -145
- package/lib/_tsup-dts-rollup.d.ts +494 -145
- package/lib/index.d.mts +26 -12
- package/lib/index.d.ts +26 -12
- package/lib/index.js +1021 -470
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +1011 -461
- package/lib/index.mjs.map +1 -1
- package/package.json +2 -2
- package/project.json +10 -2
- package/src/__tests__/container.spec.mts +1301 -0
- package/src/__tests__/factory.spec.mts +137 -0
- package/src/__tests__/injectable.spec.mts +32 -88
- package/src/__tests__/injection-token.spec.mts +333 -17
- package/src/__tests__/request-scope.spec.mts +427 -0
- package/src/__type-tests__/factory.spec-d.mts +65 -0
- package/src/__type-tests__/inject.spec-d.mts +27 -28
- package/src/__type-tests__/injectable.spec-d.mts +42 -206
- package/src/container.mts +167 -0
- package/src/decorators/factory.decorator.mts +79 -0
- package/src/decorators/index.mts +1 -0
- package/src/decorators/injectable.decorator.mts +6 -56
- package/src/enums/injectable-scope.enum.mts +5 -1
- package/src/event-emitter.mts +18 -20
- package/src/factory-context.mts +2 -10
- package/src/index.mts +3 -2
- package/src/injection-token.mts +19 -4
- package/src/injector.mts +8 -20
- package/src/interfaces/factory.interface.mts +3 -3
- package/src/interfaces/index.mts +2 -0
- package/src/interfaces/on-service-destroy.interface.mts +3 -0
- package/src/interfaces/on-service-init.interface.mts +3 -0
- package/src/registry.mts +7 -16
- package/src/request-context-holder.mts +174 -0
- package/src/service-instantiator.mts +158 -0
- package/src/service-locator-event-bus.mts +0 -28
- package/src/service-locator-instance-holder.mts +27 -16
- package/src/service-locator-manager.mts +84 -0
- package/src/service-locator.mts +548 -393
- package/src/utils/defer.mts +73 -0
- package/src/utils/get-injectors.mts +91 -78
- package/src/utils/index.mts +2 -0
- package/src/utils/types.mts +52 -0
- package/docs/concepts/injectable.md +0 -182
- package/docs/concepts/injection-token.md +0 -145
- package/src/proxy-service-locator.mts +0 -83
- package/src/resolve-service.mts +0 -41
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
# Service Lifecycle
|
|
2
|
+
|
|
3
|
+
Navios DI provides built-in support for service lifecycle management through the `OnServiceInit` and `OnServiceDestroy` interfaces. These hooks allow services to perform initialization and cleanup operations when they are created or destroyed.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Service lifecycle hooks are called automatically by the DI container:
|
|
8
|
+
|
|
9
|
+
- `onServiceInit()` - Called after the service is instantiated and all dependencies are injected
|
|
10
|
+
- `onServiceDestroy()` - Called when the service is being destroyed (e.g., during container invalidation)
|
|
11
|
+
|
|
12
|
+
## Basic Usage
|
|
13
|
+
|
|
14
|
+
### Service with Lifecycle Hooks
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { Injectable, OnServiceDestroy, OnServiceInit } from '@navios/di'
|
|
18
|
+
|
|
19
|
+
@Injectable()
|
|
20
|
+
class DatabaseService implements OnServiceInit, OnServiceDestroy {
|
|
21
|
+
private connection: any = null
|
|
22
|
+
|
|
23
|
+
async onServiceInit() {
|
|
24
|
+
console.log('Initializing database connection...')
|
|
25
|
+
this.connection = await this.connect()
|
|
26
|
+
console.log('Database connected successfully')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async onServiceDestroy() {
|
|
30
|
+
console.log('Closing database connection...')
|
|
31
|
+
if (this.connection) {
|
|
32
|
+
await this.connection.close()
|
|
33
|
+
console.log('Database connection closed')
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private async connect() {
|
|
38
|
+
// Simulate database connection
|
|
39
|
+
return new Promise((resolve) => {
|
|
40
|
+
setTimeout(() => resolve({ connected: true }), 100)
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async query(sql: string) {
|
|
45
|
+
if (!this.connection) {
|
|
46
|
+
throw new Error('Database not connected')
|
|
47
|
+
}
|
|
48
|
+
return `Query result: ${sql}`
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Using the Service
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { Container } from '@navios/di'
|
|
57
|
+
|
|
58
|
+
const container = new Container()
|
|
59
|
+
|
|
60
|
+
// Service initialization happens automatically
|
|
61
|
+
const dbService = await container.get(DatabaseService)
|
|
62
|
+
// Output: "Initializing database connection..."
|
|
63
|
+
// Output: "Database connected successfully"
|
|
64
|
+
|
|
65
|
+
// Use the service
|
|
66
|
+
const result = await dbService.query('SELECT * FROM users')
|
|
67
|
+
console.log(result) // "Query result: SELECT * FROM users"
|
|
68
|
+
|
|
69
|
+
// Service destruction happens when invalidated
|
|
70
|
+
await container.invalidate(dbService)
|
|
71
|
+
// Output: "Closing database connection..."
|
|
72
|
+
// Output: "Database connection closed"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Lifecycle Hook Details
|
|
76
|
+
|
|
77
|
+
### OnServiceInit
|
|
78
|
+
|
|
79
|
+
The `onServiceInit` method is called after:
|
|
80
|
+
|
|
81
|
+
1. The service instance is created
|
|
82
|
+
2. All constructor dependencies are injected
|
|
83
|
+
3. All property dependencies (via `asyncInject` or `inject`) are resolved
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import { inject, Injectable, OnServiceInit } from '@navios/di'
|
|
87
|
+
|
|
88
|
+
@Injectable()
|
|
89
|
+
class LoggerService {
|
|
90
|
+
log(message: string) {
|
|
91
|
+
console.log(`[LOG] ${message}`)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@Injectable()
|
|
96
|
+
class DatabaseService implements OnServiceInit {
|
|
97
|
+
private readonly logger = inject(LoggerService)
|
|
98
|
+
private connection: any = null
|
|
99
|
+
|
|
100
|
+
async onServiceInit() {
|
|
101
|
+
// Logger is already available here
|
|
102
|
+
this.logger.log('Starting database initialization...')
|
|
103
|
+
|
|
104
|
+
this.connection = await this.connect()
|
|
105
|
+
|
|
106
|
+
this.logger.log('Database initialization complete')
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private async connect() {
|
|
110
|
+
// Simulate connection
|
|
111
|
+
return new Promise((resolve) => {
|
|
112
|
+
setTimeout(() => resolve({ connected: true }), 100)
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### OnServiceDestroy
|
|
119
|
+
|
|
120
|
+
The `onServiceDestroy` method is called when:
|
|
121
|
+
|
|
122
|
+
1. The service is explicitly invalidated via `container.invalidate()`
|
|
123
|
+
2. The container is being destroyed
|
|
124
|
+
3. The service instance is being garbage collected
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import { Injectable, OnServiceDestroy } from '@navios/di'
|
|
128
|
+
|
|
129
|
+
@Injectable()
|
|
130
|
+
class CacheService implements OnServiceDestroy {
|
|
131
|
+
private cache = new Map()
|
|
132
|
+
private cleanupInterval: NodeJS.Timeout | null = null
|
|
133
|
+
|
|
134
|
+
async onServiceDestroy() {
|
|
135
|
+
console.log('Cleaning up cache service...')
|
|
136
|
+
|
|
137
|
+
// Clear the cache
|
|
138
|
+
this.cache.clear()
|
|
139
|
+
|
|
140
|
+
// Clear any intervals
|
|
141
|
+
if (this.cleanupInterval) {
|
|
142
|
+
clearInterval(this.cleanupInterval)
|
|
143
|
+
this.cleanupInterval = null
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
console.log('Cache service cleanup complete')
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
set(key: string, value: any) {
|
|
150
|
+
this.cache.set(key, value)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
get(key: string) {
|
|
154
|
+
return this.cache.get(key)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Advanced Patterns
|
|
160
|
+
|
|
161
|
+
### Service with Multiple Resources
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
import { Injectable, OnServiceDestroy, OnServiceInit } from '@navios/di'
|
|
165
|
+
|
|
166
|
+
@Injectable()
|
|
167
|
+
class ResourceManager implements OnServiceInit, OnServiceDestroy {
|
|
168
|
+
private resources: Array<{ name: string; cleanup: () => Promise<void> }> = []
|
|
169
|
+
|
|
170
|
+
async onServiceInit() {
|
|
171
|
+
console.log('Initializing resources...')
|
|
172
|
+
|
|
173
|
+
// Initialize multiple resources
|
|
174
|
+
await this.initializeDatabase()
|
|
175
|
+
await this.initializeCache()
|
|
176
|
+
await this.initializeFileSystem()
|
|
177
|
+
|
|
178
|
+
console.log('All resources initialized')
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async onServiceDestroy() {
|
|
182
|
+
console.log('Cleaning up resources...')
|
|
183
|
+
|
|
184
|
+
// Clean up in reverse order
|
|
185
|
+
for (let i = this.resources.length - 1; i >= 0; i--) {
|
|
186
|
+
const resource = this.resources[i]
|
|
187
|
+
try {
|
|
188
|
+
console.log(`Cleaning up ${resource.name}...`)
|
|
189
|
+
await resource.cleanup()
|
|
190
|
+
console.log(`${resource.name} cleaned up successfully`)
|
|
191
|
+
} catch (error) {
|
|
192
|
+
console.error(`Error cleaning up ${resource.name}:`, error)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
this.resources = []
|
|
197
|
+
console.log('All resources cleaned up')
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
private async initializeDatabase() {
|
|
201
|
+
const connection = { connected: true }
|
|
202
|
+
this.resources.push({
|
|
203
|
+
name: 'Database',
|
|
204
|
+
cleanup: async () => {
|
|
205
|
+
connection.connected = false
|
|
206
|
+
console.log('Database connection closed')
|
|
207
|
+
},
|
|
208
|
+
})
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
private async initializeCache() {
|
|
212
|
+
const cache = new Map()
|
|
213
|
+
this.resources.push({
|
|
214
|
+
name: 'Cache',
|
|
215
|
+
cleanup: async () => {
|
|
216
|
+
cache.clear()
|
|
217
|
+
console.log('Cache cleared')
|
|
218
|
+
},
|
|
219
|
+
})
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
private async initializeFileSystem() {
|
|
223
|
+
const files = ['temp1.txt', 'temp2.txt']
|
|
224
|
+
this.resources.push({
|
|
225
|
+
name: 'FileSystem',
|
|
226
|
+
cleanup: async () => {
|
|
227
|
+
// Simulate file cleanup
|
|
228
|
+
console.log(`Cleaned up files: ${files.join(', ')}`)
|
|
229
|
+
},
|
|
230
|
+
})
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Service with Conditional Initialization
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
import { Injectable, OnServiceDestroy, OnServiceInit } from '@navios/di'
|
|
239
|
+
|
|
240
|
+
@Injectable()
|
|
241
|
+
class ConditionalService implements OnServiceInit, OnServiceDestroy {
|
|
242
|
+
private initialized = false
|
|
243
|
+
private resources: any[] = []
|
|
244
|
+
|
|
245
|
+
async onServiceInit() {
|
|
246
|
+
console.log('Checking initialization conditions...')
|
|
247
|
+
|
|
248
|
+
// Check if we should initialize
|
|
249
|
+
if (await this.shouldInitialize()) {
|
|
250
|
+
await this.performInitialization()
|
|
251
|
+
this.initialized = true
|
|
252
|
+
console.log('Service initialized successfully')
|
|
253
|
+
} else {
|
|
254
|
+
console.log('Skipping initialization due to conditions')
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async onServiceDestroy() {
|
|
259
|
+
if (this.initialized) {
|
|
260
|
+
console.log('Cleaning up initialized service...')
|
|
261
|
+
await this.performCleanup()
|
|
262
|
+
this.initialized = false
|
|
263
|
+
console.log('Service cleanup complete')
|
|
264
|
+
} else {
|
|
265
|
+
console.log('No cleanup needed - service was not initialized')
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
private async shouldInitialize(): Promise<boolean> {
|
|
270
|
+
// Check environment variables, configuration, etc.
|
|
271
|
+
return process.env.NODE_ENV !== 'test'
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
private async performInitialization() {
|
|
275
|
+
// Initialize resources
|
|
276
|
+
this.resources.push(await this.createResource('Resource1'))
|
|
277
|
+
this.resources.push(await this.createResource('Resource2'))
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
private async performCleanup() {
|
|
281
|
+
// Clean up resources
|
|
282
|
+
for (const resource of this.resources) {
|
|
283
|
+
await resource.cleanup()
|
|
284
|
+
}
|
|
285
|
+
this.resources = []
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
private async createResource(name: string) {
|
|
289
|
+
return {
|
|
290
|
+
name,
|
|
291
|
+
cleanup: async () => console.log(`Cleaned up ${name}`),
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Service with Error Handling
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
import { Injectable, OnServiceDestroy, OnServiceInit } from '@navios/di'
|
|
301
|
+
|
|
302
|
+
@Injectable()
|
|
303
|
+
class RobustService implements OnServiceInit, OnServiceDestroy {
|
|
304
|
+
private connection: any = null
|
|
305
|
+
private retryCount = 0
|
|
306
|
+
private maxRetries = 3
|
|
307
|
+
|
|
308
|
+
async onServiceInit() {
|
|
309
|
+
console.log('Initializing robust service...')
|
|
310
|
+
|
|
311
|
+
try {
|
|
312
|
+
await this.initializeWithRetry()
|
|
313
|
+
console.log('Service initialized successfully')
|
|
314
|
+
} catch (error) {
|
|
315
|
+
console.error('Failed to initialize service:', error)
|
|
316
|
+
// Don't throw - let the service be created but mark it as failed
|
|
317
|
+
this.connection = null
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
async onServiceDestroy() {
|
|
322
|
+
console.log('Cleaning up robust service...')
|
|
323
|
+
|
|
324
|
+
try {
|
|
325
|
+
if (this.connection) {
|
|
326
|
+
await this.connection.close()
|
|
327
|
+
console.log('Connection closed successfully')
|
|
328
|
+
}
|
|
329
|
+
} catch (error) {
|
|
330
|
+
console.error('Error during cleanup:', error)
|
|
331
|
+
// Don't throw - cleanup should be best effort
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
private async initializeWithRetry(): Promise<void> {
|
|
336
|
+
for (let i = 0; i < this.maxRetries; i++) {
|
|
337
|
+
try {
|
|
338
|
+
this.connection = await this.connect()
|
|
339
|
+
this.retryCount = i
|
|
340
|
+
return
|
|
341
|
+
} catch (error) {
|
|
342
|
+
console.log(`Initialization attempt ${i + 1} failed:`, error.message)
|
|
343
|
+
if (i === this.maxRetries - 1) {
|
|
344
|
+
throw error
|
|
345
|
+
}
|
|
346
|
+
// Wait before retry
|
|
347
|
+
await new Promise((resolve) => setTimeout(resolve, 1000 * (i + 1)))
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
private async connect() {
|
|
353
|
+
// Simulate connection that might fail
|
|
354
|
+
return new Promise((resolve, reject) => {
|
|
355
|
+
setTimeout(() => {
|
|
356
|
+
if (Math.random() > 0.3) {
|
|
357
|
+
// 70% success rate
|
|
358
|
+
resolve({ connected: true })
|
|
359
|
+
} else {
|
|
360
|
+
reject(new Error('Connection failed'))
|
|
361
|
+
}
|
|
362
|
+
}, 100)
|
|
363
|
+
})
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
async performOperation() {
|
|
367
|
+
if (!this.connection) {
|
|
368
|
+
throw new Error('Service not properly initialized')
|
|
369
|
+
}
|
|
370
|
+
return 'Operation completed'
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
## Lifecycle with Dependencies
|
|
376
|
+
|
|
377
|
+
### Service Depending on Other Services with Lifecycle
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
import { inject, Injectable, OnServiceDestroy, OnServiceInit } from '@navios/di'
|
|
381
|
+
|
|
382
|
+
@Injectable()
|
|
383
|
+
class LoggerService implements OnServiceInit, OnServiceDestroy {
|
|
384
|
+
private logFile: any = null
|
|
385
|
+
|
|
386
|
+
async onServiceInit() {
|
|
387
|
+
console.log('Initializing logger...')
|
|
388
|
+
this.logFile = { name: 'app.log', open: true }
|
|
389
|
+
console.log('Logger initialized')
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
async onServiceDestroy() {
|
|
393
|
+
console.log('Closing logger...')
|
|
394
|
+
if (this.logFile) {
|
|
395
|
+
this.logFile.open = false
|
|
396
|
+
console.log('Logger closed')
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
log(message: string) {
|
|
401
|
+
console.log(`[LOG] ${message}`)
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
@Injectable()
|
|
406
|
+
class DatabaseService implements OnServiceInit, OnServiceDestroy {
|
|
407
|
+
private readonly logger = inject(LoggerService)
|
|
408
|
+
private connection: any = null
|
|
409
|
+
|
|
410
|
+
async onServiceInit() {
|
|
411
|
+
// Logger is already initialized at this point
|
|
412
|
+
this.logger.log('Initializing database...')
|
|
413
|
+
|
|
414
|
+
this.connection = await this.connect()
|
|
415
|
+
|
|
416
|
+
this.logger.log('Database initialized')
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
async onServiceDestroy() {
|
|
420
|
+
this.logger.log('Closing database...')
|
|
421
|
+
|
|
422
|
+
if (this.connection) {
|
|
423
|
+
await this.connection.close()
|
|
424
|
+
this.logger.log('Database closed')
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
private async connect() {
|
|
429
|
+
return new Promise((resolve) => {
|
|
430
|
+
setTimeout(() => resolve({ connected: true }), 100)
|
|
431
|
+
})
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
## Best Practices
|
|
437
|
+
|
|
438
|
+
### 1. Always Check Resource State
|
|
439
|
+
|
|
440
|
+
```typescript
|
|
441
|
+
// ✅ Good: Check if resource exists before cleanup
|
|
442
|
+
async onServiceDestroy() {
|
|
443
|
+
if (this.connection) {
|
|
444
|
+
await this.connection.close()
|
|
445
|
+
this.connection = null
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// ❌ Avoid: Assuming resource exists
|
|
450
|
+
async onServiceDestroy() {
|
|
451
|
+
await this.connection.close() // Might throw if connection is null
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### 2. Handle Errors Gracefully
|
|
456
|
+
|
|
457
|
+
```typescript
|
|
458
|
+
// ✅ Good: Handle errors without throwing
|
|
459
|
+
async onServiceDestroy() {
|
|
460
|
+
try {
|
|
461
|
+
if (this.connection) {
|
|
462
|
+
await this.connection.close()
|
|
463
|
+
}
|
|
464
|
+
} catch (error) {
|
|
465
|
+
console.error('Error during cleanup:', error)
|
|
466
|
+
// Don't throw - cleanup should be best effort
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### 3. Use Async/Await Consistently
|
|
472
|
+
|
|
473
|
+
```typescript
|
|
474
|
+
// ✅ Good: Use async/await for consistency
|
|
475
|
+
async onServiceInit() {
|
|
476
|
+
this.connection = await this.connect()
|
|
477
|
+
this.cache = await this.initializeCache()
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// ❌ Avoid: Mixing promises and async/await
|
|
481
|
+
async onServiceInit() {
|
|
482
|
+
this.connection = await this.connect()
|
|
483
|
+
this.cache = this.initializeCache() // Missing await
|
|
484
|
+
}
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
### 4. Clean Up in Reverse Order
|
|
488
|
+
|
|
489
|
+
```typescript
|
|
490
|
+
// ✅ Good: Clean up in reverse order of initialization
|
|
491
|
+
async onServiceDestroy() {
|
|
492
|
+
// Clean up in reverse order
|
|
493
|
+
await this.cleanupResource3()
|
|
494
|
+
await this.cleanupResource2()
|
|
495
|
+
await this.cleanupResource1()
|
|
496
|
+
}
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
### 5. Don't Block Initialization
|
|
500
|
+
|
|
501
|
+
```typescript
|
|
502
|
+
// ✅ Good: Don't block on non-critical operations
|
|
503
|
+
async onServiceInit() {
|
|
504
|
+
// Critical initialization
|
|
505
|
+
this.connection = await this.connect()
|
|
506
|
+
|
|
507
|
+
// Non-critical operations can be done asynchronously
|
|
508
|
+
this.initializeMetrics().catch(error => {
|
|
509
|
+
console.error('Failed to initialize metrics:', error)
|
|
510
|
+
})
|
|
511
|
+
}
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
## API Reference
|
|
515
|
+
|
|
516
|
+
### OnServiceInit Interface
|
|
517
|
+
|
|
518
|
+
```typescript
|
|
519
|
+
interface OnServiceInit {
|
|
520
|
+
onServiceInit(): Promise<void> | void
|
|
521
|
+
}
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
### OnServiceDestroy Interface
|
|
525
|
+
|
|
526
|
+
```typescript
|
|
527
|
+
interface OnServiceDestroy {
|
|
528
|
+
onServiceDestroy(): Promise<void> | void
|
|
529
|
+
}
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
### Lifecycle Order
|
|
533
|
+
|
|
534
|
+
1. **Service Creation**: Constructor is called
|
|
535
|
+
2. **Dependency Injection**: Dependencies are injected
|
|
536
|
+
3. **onServiceInit**: Called after all dependencies are resolved
|
|
537
|
+
4. **Service Usage**: Service is ready for use
|
|
538
|
+
5. **onServiceDestroy**: Called when service is being destroyed
|
|
539
|
+
6. **Cleanup**: Resources are cleaned up
|