foundations/net/docs/AUTO_DISPOSAL_GUIDE.md
This guide explains how to properly use auto-disposal with the createNetworkClient() function.
The NetworkClientWithAgents class implements JavaScript's explicit resource management proposal via Symbol.dispose and Symbol.asyncDispose. This provides automatic cleanup of resources when clients go out of scope.
await usingawait using for:// Example: Simple client usage with auto-disposal
async function fetchData() {
await using client = createNetworkClient('localhost:3737')
await client.waitConnection(5000)
const container = await client.get('my-service' as ContainerKind, {})
const result = await container.request('getData')
return result
// Client automatically disposed here
}
await using for:serveAgent()// Example: Long-running service (DON'T use 'await using')
class MyService {
private client: ReturnType<typeof createNetworkClient> | null = null
async start() {
// Keep strong reference - NO 'await using'
this.client = createNetworkClient('localhost:3737')
await this.client.waitConnection(5000)
// Serve containers
await this.client.serveAgent('localhost:3738', {
'my-container': myContainerFactory
})
console.log('Service started - will run indefinitely')
}
async stop() {
// Manual cleanup when ready
if (this.client) {
await this.client.close()
this.client = null
}
}
}
// Usage
const service = new MyService()
await service.start()
// Graceful shutdown
process.on('SIGTERM', () => service.stop())
process.on('SIGINT', () => service.stop())
// Keep running
await new Promise(() => {})
When you use await using, the client will be automatically disposed:
async function example() {
await using client = createNetworkClient('localhost:3737')
// If an error occurs here...
throw new Error('Something went wrong')
// ...client.close() is still called automatically
}
For long-running services, manage the lifecycle manually:
// Create without auto-disposal
const client = createNetworkClient('localhost:3737')
// Use the client...
await client.waitConnection(5000)
// Manual cleanup when done
await client.close()
All example scripts should use await using for automatic cleanup:
async function main() {
// Setup infrastructure (servers, agents)
const server = new NetworkServer(...)
const agent = new AgentImpl(...)
// Client with auto-disposal
await using client = createNetworkClient('localhost:3737')
await client.register(agent)
// Do work...
// Manual cleanup of infrastructure
await server.close()
}
Production services should use manual lifecycle management:
class ProductionService {
private client: NetworkClient | null = null
async start() {
this.client = createNetworkClient(config.networkUrl)
await this.client.waitConnection()
await this.setupContainers()
// Setup signal handlers
process.on('SIGTERM', () => this.shutdown())
process.on('SIGINT', () => this.shutdown())
}
async shutdown() {
console.log('Graceful shutdown initiated...')
if (this.client) {
await this.client.close()
}
process.exit(0)
}
}
If you have existing code using manual client.close():
const client = createNetworkClient('localhost:3737')
try {
await client.waitConnection(5000)
// ... use client ...
} finally {
await client.close()
}
await using client = createNetworkClient('localhost:3737')
await client.waitConnection(5000)
// ... use client ...
// Automatically closed
await using in long-running services// BAD: Service will stop when function returns!
async function startService() {
await using client = createNetworkClient('localhost:3737')
await client.serveAgent('localhost:3738', factories)
// Client disposed when function returns - service stops!
}
// GOOD: Service keeps running
let client: NetworkClient | null = null
async function startService() {
client = createNetworkClient('localhost:3737')
await client.serveAgent('localhost:3738', factories)
// Service continues running
}
async function stopService() {
if (client) {
await client.close()
client = null
}
}
await using for automatic cleanupawait using for cleaner codeThe auto-disposal feature makes resource management simpler and safer for temporary client usage while still allowing full control for production services.