davianspace_hosting 1.0.3
davianspace_hosting: ^1.0.3 copied to clipboard
Enterprise-grade hosting framework for Dart. Unifies configuration, logging, dependency injection, and lifecycle management into a coherent application model.
// Example code intentionally uses print for demonstration.
// ignore_for_file: avoid_print
import 'dart:async';
import 'package:davianspace_configuration/davianspace_configuration.dart';
import 'package:davianspace_hosting/davianspace_hosting.dart';
import 'package:davianspace_logging/davianspace_logging.dart';
// =============================================================================
// Example 1 — Minimal CLI application
// =============================================================================
/// Demonstrates the simplest possible hosted application.
///
/// ```bash
/// dart run example/example.dart
/// ```
Future<void> minimalExample() async {
final host =
await createDefaultBuilder().configureServices((context, services) {
// Register application services here.
services.addSingletonFactory<GreetingService>(
(sp) => GreetingService(
sp.getRequired<LoggerFactory>().createLogger('GreetingService'),
),
);
}).build();
// Use services before running.
final greeter = host.services.getRequired<GreetingService>();
greeter.greet('World');
// Run blocks until SIGINT/SIGTERM.
await host.run();
}
final class GreetingService {
GreetingService(this._logger);
final Logger _logger;
void greet(String name) {
_logger.info('Hello, $name!');
}
}
// =============================================================================
// Example 2 — Background worker with hosted services
// =============================================================================
/// Demonstrates a background worker application using hosted services.
Future<void> backgroundWorkerExample() async {
final host =
await createDefaultBuilder().configureConfiguration((context, config) {
config.addInMemory({
'Worker:IntervalSeconds': '5',
'Worker:Name': 'DataSync',
});
}).configureServices((context, services) {
// Register the background worker as a hosted service.
services.addHostedService(
(sp) => DataSyncWorker(
name: sp.getRequired<Configuration>()['Worker:Name'] ?? 'Default',
intervalSeconds: int.parse(
sp.getRequired<Configuration>()['Worker:IntervalSeconds'] ?? '10',
),
logger: sp.getRequired<LoggerFactory>().createLogger('DataSyncWorker'),
),
);
// Register a second worker.
services.addHostedService(
(sp) => HealthCheckWorker(
logger:
sp.getRequired<LoggerFactory>().createLogger('HealthCheckWorker'),
),
);
}).configureLogging((context, logging) {
logging.addConsole().setMinimumLevel(LogLevel.debug);
}).build();
// Lifecycle hooks.
final lifetime = host.services.getRequired<ApplicationLifetime>();
lifetime.onStarted(() => print('[Lifecycle] Application started'));
lifetime.onStopping(() => print('[Lifecycle] Application stopping...'));
lifetime.onStopped(() => print('[Lifecycle] Application stopped'));
await host.run();
}
/// A hosted service that periodically syncs data.
final class DataSyncWorker implements HostedService {
DataSyncWorker({
required this.name,
required this.intervalSeconds,
required Logger logger,
}) : _logger = logger;
final String name;
final int intervalSeconds;
final Logger _logger;
Timer? _timer;
@override
Future<void> start() async {
_logger.info(
'DataSyncWorker "$name" starting (interval: ${intervalSeconds}s)',
);
_timer = Timer.periodic(
Duration(seconds: intervalSeconds),
(_) => _logger.info('DataSyncWorker "$name" syncing...'),
);
}
@override
Future<void> stop() async {
_logger.info('DataSyncWorker "$name" stopping');
_timer?.cancel();
_timer = null;
}
}
/// A hosted service that performs periodic health checks.
final class HealthCheckWorker implements HostedService {
HealthCheckWorker({required Logger logger}) : _logger = logger;
final Logger _logger;
Timer? _timer;
@override
Future<void> start() async {
_logger.info('HealthCheckWorker starting');
_timer = Timer.periodic(
const Duration(seconds: 15),
(_) => _logger.debug('Health check: OK'),
);
}
@override
Future<void> stop() async {
_logger.info('HealthCheckWorker stopping');
_timer?.cancel();
_timer = null;
}
}
// =============================================================================
// Example 3 — Configuration-driven application
// =============================================================================
/// Demonstrates advanced configuration with environment-aware setup.
Future<void> configurationExample() async {
final host =
await createDefaultBuilder().configureConfiguration((context, config) {
config.addInMemory({
'Database:Host': 'localhost',
'Database:Port': '5432',
'Database:Name': 'myapp',
'App:Name': 'ConfigDemo',
}).addEnvironmentVariables(prefix: 'MYAPP_');
}).configureServices((context, services) {
// Read config during registration.
final dbSection = context.configuration.getSection('Database');
final dbHost = dbSection['Host'] ?? 'localhost';
final dbPort = int.parse(dbSection['Port'] ?? '5432');
services.addSingletonFactory<DatabaseConnection>(
(sp) => DatabaseConnection(host: dbHost, port: dbPort),
);
// Environment-specific services.
if (context.isDevelopment) {
services.addSingletonFactory<CacheService>(
(_) => InMemoryCacheService(),
);
} else {
services.addSingletonFactory<CacheService>(
(_) => RedisCacheService(),
);
}
}).build();
final db = host.services.getRequired<DatabaseConnection>();
print('Connected to ${db.host}:${db.port}');
await host.dispose();
}
// Stub classes for the configuration example.
final class DatabaseConnection {
DatabaseConnection({required this.host, required this.port});
final String host;
final int port;
}
abstract interface class CacheService {}
final class InMemoryCacheService implements CacheService {}
final class RedisCacheService implements CacheService {}
// =============================================================================
// main
// =============================================================================
void main() async {
print('=== DavianSpace Hosting Examples ===\n');
// Run the minimal example (uses host.run which blocks on signals,
// so for demo purposes we just build and dispose).
print('--- Configuration Example ---');
await configurationExample();
print('\n--- Background Worker Example ---');
print('(Run backgroundWorkerExample() directly for a live demo)');
print('\nDone.');
}