Starting the daemon
The php bin/console opcua:session command — every option, every wire to Symfony's logger / cache / event dispatcher.
The bundle ships a Symfony console command that launches the daemon with Symfony-side wiring (logger, cache, event dispatcher) flowing in:
php bin/console opcua:session
That reads session_manager.* from
config/packages/php_opcua_symfony_opcua.yaml and starts the
daemon. Blocks until Ctrl+C or signalled.
Why the console command?
Three things php bin/console opcua:session does that
vendor/bin/opcua-session-manager doesn't:
- Wires
LoggerInterfacefrom the configured Monolog channel (session_manager.log_channel→monolog.logger.<name>). - Wires
CacheInterfacefrom the configured Symfony cache pool (session_manager.cache_pool→cache.appby default, wrapped inPsr16Cache). - Wires
EventDispatcherInterface— Symfony's dispatcher, for auto-publish.
Run the console command unless you have a specific reason not to.
Options
| Option | Default | Effect |
|---|---|---|
--timeout=<sec> |
session_manager.timeout |
Idle session timeout |
--cleanup-interval=<sec> |
session_manager.cleanup_interval |
Reaper loop period |
--max-sessions=<n> |
session_manager.max_sessions |
Cap on concurrent sessions |
--socket-mode=<oct> |
session_manager.socket_mode |
Unix socket permissions |
CLI flags override YAML config for that one invocation. All
flags accept --socket-mode=0660 octal form.
Examples
Development
php bin/console opcua:session
Pure defaults. Socket at var/opcua-session-manager.sock.
Custom timeout
php bin/console opcua:session --timeout=1800 --max-sessions=50
Production-style
Production typically pulls all settings from YAML; the command runs with no flags:
APP_ENV=prod php bin/console opcua:session
…with config/packages/prod/php_opcua_symfony_opcua.yaml:
php_opcua_symfony_opcua:
session_manager:
socket_path: /var/run/opcua/sessions.sock
socket_mode: 0660
timeout: 600
cleanup_interval: 30
max_sessions: 100
auth_token: '%env(secret:OPCUA_AUTH_TOKEN)%'
log_channel: opcua
cache_pool: cache.redis
auto_publish: true
allowed_cert_dirs:
- /etc/opcua/certs
- /var/lib/opcua/trust
Run under systemd — see Production supervisor.
What happens at start
- Boot Symfony (kernel boot, container compile).
- Resolve the log channel and cache pool services.
- Resolve
EventDispatcherInterfaceifauto_publishis on. - Construct
SessionManagerDaemonwith the wired deps. - Pre-connect configured connections if
auto_connectis on on individual connections. - Bind the socket, set permissions, start listening.
- Block in the event loop.
First log line:
[2026-05-15 10:00:00] opcua.INFO: SessionManagerDaemon started
socket=/var/run/opcua/sessions.sock mode=0660
timeout=600 cleanup=30 max_sessions=100 auto_publish=true
Auto-connect on startup
Connections with auto_connect: true and a subscriptions:
block are connected on the first event loop tick:
php_opcua_symfony_opcua:
session_manager:
auto_publish: true
connections:
plc-line-a:
endpoint: '%env(OPCUA_LINE_A)%'
auto_connect: true
subscriptions:
-
publishing_interval: 500.0
monitored_items:
- { node_id: 'ns=2;s=Speed', client_handle: 1 }
- { node_id: 'ns=2;s=Temperature', client_handle: 2 }
The daemon opens the session, creates the subscription, and starts publishing events to Symfony's EventDispatcher. See Auto-publish.
Stopping the daemon
Send SIGTERM for graceful shutdown:
sudo systemctl stop opcua-session-manager
# or by PID
kill -TERM <pid>
SIGINT (Ctrl+C) does the same. On exit the daemon:
- Stops accepting new connections.
- Closes all OPC UA sessions cleanly.
- Unlinks the Unix socket file.
- Exits with status 0.
Restarting
After deploying new code, restart the daemon — it caches the autoload index at boot:
sudo systemctl restart opcua-session-manager
This briefly closes all daemon-held sessions. Symfony processes reconnect on the next IPC call.
Multiple daemons
The opcua:session command does not accept a
--socket-path flag — its only options are --timeout,
--cleanup-interval, --max-sessions, --socket-mode. To run
multiple daemons on different socket paths, wire
session_manager.socket_path through an env var and launch each
daemon with a different env value:
OPCUA_SOCKET_PATH=/var/run/opcua/tenant-a.sock php bin/console opcua:session &
OPCUA_SOCKET_PATH=/var/run/opcua/tenant-b.sock php bin/console opcua:session &
With the bundle config pointing at %env(OPCUA_SOCKET_PATH)%:
php_opcua_symfony_opcua:
session_manager:
socket_path: '%env(OPCUA_SOCKET_PATH)%'
See Recipes · Multi-plant tenant.
Running outside Symfony
If you need the daemon without Symfony's runtime:
vendor/bin/opcua-session-manager \
--socket /var/run/opcua/sessions.sock \
--timeout 600 \
--auth-token "${OPCUA_AUTH_TOKEN}"
You lose the Symfony wiring — no Monolog channel, no Symfony cache pool, no EventDispatcher. The daemon falls back to a null logger and in-memory cache. For most production needs the console command is the right choice.
Where to read next
- Auto-publish — declarative subscriptions
- EventDispatcher delivery.
- Production supervisor — systemd / Supervisor units for the daemon.
- Monitoring the daemon — liveness, metrics, logs.