dart_service_manager 1.4.0
dart_service_manager: ^1.4.0 copied to clipboard
Declare services in a Dart package, compile them to native executables, and install and manage them as native operating-system services on Linux (systemd), macOS (launchd) and Windows (SCM). Ships a r [...]
1.4.0 #
- Fix
forCurrentExecutablereinstalls carrying a stale runtime script. The registry recorded the full argument vector,dart <script> <command…>, so a consumer that reinstalled fromRegistryEntry.argumentsfed the old script back in. The 1.3.1 guard only caught an exact match, so it missed two cases. A service installed under the Dart VM and reinstalled from an AOT build (for example a Dart 3.12dart installapp bundle) ran<binary> <old snapshot> <command…>. After an SDK upgrade renamed the pub-cache snapshot, it randart <new snapshot> <old snapshot> <command…>. - New
ServiceDescriptor.scriptPathandRegistryEntry.scriptPathrecord the Dart script separately, andforCurrentExecutablesets it.ServiceDescriptor.commandArgumentsgives the command without the script. - Behaviour change:
RegistryEntry.argumentsis now the command alone. The newRegistryEntry.commandLineis the full vector passed to the binary. Reinstalling fromentry.argumentsnow does the right thing with no change in the consumer. Registries written by earlier releases are migrated on read: a Dart VM entry's first argument becomesscriptPath. resolveSelfExecutablealso drops leading runtime scripts already in the arguments before adding the current one. It drops the current script, and any absolute.snapshot,.dillor.dartpath. This repairs services already installed with a stale or doubled script. The function now also returns thescriptit applied, and recognisesdart.exepaths on any host.- The Task Scheduler driver keeps
scriptPathpointing at the staged runtime copy. - README: the
reconfigureexample rebuilt a descriptor withcopyWith(arguments: …), which drops the script under the Dart VM. It now usesforCurrentExecutable, and a reinstall example was added. - Fix launchd reporting a stopped service as
failed.launchctl stopends the service with SIGTERM, so launchd reportsLastExitStatus = 15, and every nonzero value was read as a failure. The value is a rawwaitpidstatus, so a SIGTERM stop now reads asstopped. Real failures (a nonzero exit code, which is shifted left by 8 bits, or a crash signal) still read asfailed. - New tests run against the host's real init system,
test/integration/host_service_test.dart. They install, stop, start, reinstall and uninstall user-scoped services undersystemd --userand launchd, including reinstalls across a Dart VM script change and a switch to a native binary. Theos-*tags are still skipped by default; the newhostpreset runs them (dart test -P host), and the new CIhostjob runs them on Ubuntu and macOS. Before this,-t os-macosalone never lifted the skip, so these tests never ran. - More unit and integration coverage: lifecycle operations for 1.3.x registry
entries, upgrading a 1.3.x registry file on disk, reinstalling a service the
OS no longer knows,
forCurrentExecutableitself,isRuntimeScript, and a real-process test forSystemProcessRunner. - Adopt super parameters in the exception classes; the current SDK's
use_super_parameterslint was failingdart analyze --fatal-infosin CI.
1.3.1 #
- Fix a
forCurrentExecutablereinstall crash-loop under the Dart VM (JIT / pub-cache snapshot).resolveSelfExecutableprependedPlatform.scriptto the arguments unconditionally, so re-deriving a descriptor from already-resolved arguments (as a reinstall does, replaying the registry's stored arguments) doubled the script:dart <snapshot> <snapshot> <command> …. The service then saw the extra snapshot path as an argument before its command and exited, triggering an endlessRestart=alwaysloop. The prepend is now idempotent — if the arguments already start with the script it is not added again. Affects every platform (systemd, launchd, Windows SCM and Task Scheduler), since the fix is in the shared descriptor model.
1.3.0 #
- Add a Windows Task Scheduler backend (
WindowsTaskSchedulerDriver, selected viaWindowsServiceBackend.taskScheduler). Unlike the SCM driver, it runs plain console executables as background daemons without the in-process service-control dispatcher the SCM requires (which kills such programs with error 1053), and stages a private copy of the runtime so a Windows-locked pub-cache snapshot can still be refreshed.ServiceDriverFactoryandDartServiceManager.forCurrentPlatformtake awindowsBackendparameter (defaultserviceControlManager, unchanged). - Add
DartServiceManager.describe()returning aServiceInfo(recorded parameters + live status + the rendered native definition), andDartServiceManager.reinstall()(clean teardown-then-recreate that tolerates a missing prior install).
1.2.2 #
- Fix a destructive bug where
uninstallcould delete an externally-provided executable — including the Dart VM itself (/usr/lib/dart/bin/dart) for aforCurrentExecutable/dart pub global activateinstall. Uninstall now only deletes binaries the manager compiled into its own managed directory;installDescriptortargets, manifestexecutable:paths and the Dart VM are left untouched.
1.2.1 #
- Fix persistent user systemd on Linux when the process inherited an
XDG_RUNTIME_DIRbelonging to a different user (common under sudo/su or deploy scripts): the runtime directory is now derived from the detected uid (/run/user/<uid>) and an inherited value is honoured only when it matches, sosystemctl --userno longer hits another user's bus and fails withFailed to connect to bus: Permission denied. That error is now recognised with an actionable hint, and a warning is emitted when a mismatchedXDG_RUNTIME_DIRis overridden.
1.2.0 #
-
Persistent user-level systemd (Linux): user-scoped installs now auto-configure the per-user systemd environment so services install, enable, start, and survive logout/reboot. A new
UserSystemdManager(ensurePersistentUserSystemd()) detectssystemctl/loginctl, the current user/uid, lingering, the user D-Bus bus, andXDG_RUNTIME_DIR; enables lingering viasudo -n loginctl enable-lingerwhen possible (warning with the manual command otherwise); and returns a detailedUserSystemdStatus(diagnostics + actionable warnings). The systemd driver runs it before user-scoped installs and passes a resolvedXDG_RUNTIME_DIRto allsystemctl --usercalls, fixingFailed to connect to bus: …errors. Linux only, idempotent, never assumes root. -
Scope/privilege warning:
installnow detects a mismatch between the requested scope and the current privilege level — running undersudo/root with the default user scope (user services fail as root), or a system-scoped install without elevation — and warns with the fix, then proceeds. Backed by a new injectablePrivilegeChecker(id -u/net session). -
The CLI now shows warnings by default (info/debug still require
--verbose). -
Added
--systemas a shorthand for--scope system.
1.1.0 #
First-class third-party / imperative integration.
- Imperative install:
DartServiceManager.installDescriptor(descriptor, {startNow, force})installs an already-built executable as a service — bypassing package resolution, manifest loading and compilation — with caller-supplied arguments, environment and runtime policy. ServiceDescriptor.forCurrentExecutable(...): install the currently running program (Platform.resolvedExecutable) as a service, handling the JIT (dart <script>) vs AOT-binary distinction.- Runtime policy on
ServiceDescriptor/ServiceInstallConfigand thedart_services:manifest:workingDirectory,restart(always/on-failure/never, newRestartPolicyenum),restartDelay,autoStart,stopTimeout,environmentFile. All default to the previous behaviour, so existing units/plists render unchanged. - Manifest
executable:as an alternative toscript:— install a pre-built binary without compiling. - Environment-file support (systemd
EnvironmentFile=); drivers exposesupportsEnvironmentFileand reject it where unsupported (launchd, Windows). render()/--dry-run: drivers can render the native definition (systemd unit, launchd plist,sccommand) without touching the system;DartServiceManager.renderDefinition(...)andinstall --executable --dry-runexpose it.reconfigure(descriptor): re-apply a changed descriptor, preserving the running state.- The registry now persists the full descriptor (args/env/description/policy), so lifecycle, listing and reconfigure work without a manifest. Registries written by 1.0.x still load.
- CLI:
install --executable <path>,--start-now,--dry-run,--restart,--restart-delay,--working-dir,--env-file,--no-auto-start,--force. - Windows services now configure SCM failure/restart actions to match the restart policy.
Potentially breaking: two new sealed exception subclasses —
PermissionDeniedException and ServiceAlreadyInstalledException — are added
to ServiceManagerException. Code that does an exhaustive switch over the
exception hierarchy must handle the new cases.
1.0.1 #
- Add a Shelf HTTP server example (
example/shelf_server) showing a real web server declared as a service and managed end-to-end, with gracefulSIGTERM/SIGINTshutdown. - Document package-wide operations in the README: a bare
packagereference (no:service) targets every service of the package — includinguninstall— and uninstalling deletes each service's cached native binary.
1.0.0 #
Initial release.
- Declare services in a package's
pubspec.yamlvia adart_services:section. - Compile service entrypoints to native executables with
dart compile exe, cached and rebuilt on change. - Install, uninstall, start, stop, pause, resume, restart and query services
through the
DartServiceManagerDart API and thedart-serviceCLI. - Platform drivers for Linux (systemd), macOS (launchd) and Windows (SCM)
behind a single
PlatformServiceDriverabstraction. - User- and system-scoped installation (
ServiceScope), defaulting to user. - A persistent JSON service registry behind a
ServiceRegistryrepository abstraction, with atomic writes and per-platform storage locations. - Structured, injectable logging (
ServiceLogger,LogLevel). - Sealed exception hierarchy with stable, machine-readable error codes.