win32service/service-library
A PHP library for building and managing native Windows services. It provides a structured service base class, configuration, and lifecycle helpers on top of the win32service extension, making it simpler to run long-lived PHP daemons as Windows services.
This library is the ergonomic layer on top of the win32service PECL extension — it gives you a driver class, service state/control wrappers, install/uninstall utilities, and a small CLI so you stop hand-rolling win32_start_service_ctrl_dispatcher() calls. It is Windows-only; you cannot exercise it from WSL or a Linux container.
Minimal path:
win32service extension enabled in php.ini. Confirm with php -m | findstr win32service. If it isn't loaded, nothing else works.composer require win32service/service-library (v1.1.0 or later — the documentation was rewritten in this release, so read the new README/docs before the blog posts you'll find via search).ServiceDriver subclass example in the docs — that is the class you extend and the only place your application logic belongs. Skim the shipped CLI commands (install / uninstall / start / stop / status) second; they're the whole operational surface.services.msc.php bin\my-service.php) and watch it loop before you ever install it as a service. Debugging a service through the Event Log is an order of magnitude slower.Keep the driver thin, delegate to Laravel. The driver callbacks (onStart, onStop, onShutdown, onPreshutdown, pause/continue, interrogate) should bootstrap bootstrap/app.php, resolve the console kernel, and hand off — either Artisan::call('your:command') or the resolved command instance. Don't reimplement application wiring inside the callback.
Long-running loop pattern. Start the work, then loop on status checks with a sleep() tick so the service stays responsive to stop/pause requests. Anything that blocks indefinitely inside onStart makes the service unmanageable and eventually gets it killed by the SCM.
New in v1.1.0 — preshutdown. You can now accept SERVICE_CONTROL_PRESHUTDOWN, which gives you advance notice before the system begins shutting services down in force. Register the preshutdown handler and use it to flush buffers, close DB connections, and cancel in-flight jobs cleanly. It only fires on Vista / Server 2008 or newer, and it is subject to the separate preshutdown timeout — treat it as "finish quickly", not "second chance to do real work".
Install-time configuration as code. Drive install from a config file (service name, display name, description, binPath, dependencies, startup type, recovery/restart actions, service account) checked into the repo. Re-running install/uninstall must be idempotent — treat it as a deployment step, not a one-off manual action.
Logging is not optional. A Windows service has no console and no inherited stdout. Wire a Monolog file or rotating handler before anything else in onStart, with an absolute path and a directory the service account can write to. Everything you'd normally echo goes there.
Reconnect on restart. onStart can run many times over the service's life (recovery actions, reboots). Assume stale state: reconnect DB/cache clients, and use a mutex/lock file so a restart never leaves two worker instances competing for the same queue.
Recovery options are your supervisor. Configure restart-on-failure actions at install time rather than writing your own crash supervisor — that's what the SCM is for. The library's restart/recovery configuration is the integration point.
Operational flow: install → start → status → (deploy) stop → install → start. Script it for your deploy pipeline; don't click through services.msc.
win32service extension-facing signature was updated; if you're on an older extension build you can get type/signature errors that only appear at service runtime. Pin the extension version in your provisioning docs and test the upgrade on the target host, not just your dev box.start/stop may work unelevated, but don't build a workflow that depends on it.%PATH%, %USERPROFILE%, and working directory than your interactive shell. Absolute paths everywhere; set any required environment variables explicitly in the service config.C:\Program Files\PHP\php.exe unquoted in the service binary path is a classic "service installs then immediately fails with error 1053" cause.onStop drains a queue, cap the drain and emit status checkpoints so the SCM sees progress.exit()/die() inside a callback. Let the driver return; an uncaught exception in a callback can leave the SCM with a service stuck in STOP_PENDING until timeout.sc query <name> / sc qc <name> for the SCM's view → Windows Event Viewer → application log file. Error 1053, 1064, and 1073 each point at a different one of the above (timeout, bad binPath, already-marked-for-deletion) — check the code before rewriting code.install failing with "marked for deletion".How can I help you explore Laravel packages today?