systemd Integration (clib.systemd)

Linux only. This module dlopens libsystemd and will throw at import time on systems where the library is absent.

import clib.systemd as systemd; provides two things: the sd_notify readiness protocol (READY, WATCHDOG, STATUS) and structured journald logging. Together these are the standard integration points for a long-running process managed by systemd.

The module uses the FFI layer so the ffi capability must be enabled.

Capability

Add to geblang.yaml:

permissions:
  ffi:
    enabled: true
    libraries:
      - glob: libsystemd*

For a standalone script:

geblang --allow-ffi 'libsystemd*' script.gb

Functions

notify(string state): bool

Raw sd_notify call. state is a newline-separated set of assignments ("READY=1", "STATUS=serving 12 requests"). Returns true if the notification was delivered to the service manager, false if the process is not running under systemd. Calling this outside a systemd service is safe and returns false.

ready(): bool

Sends READY=1. Call this once the process has finished initialisation and is ready to accept work. Equivalent to notify("READY=1").

watchdog(): bool

Sends WATCHDOG=1. Call periodically (at most half the watchdog interval) to prevent the service manager from restarting the process.

status(string text): bool

Sets the free-form status line visible in systemctl status. The text becomes STATUS=<text>. Useful for progress updates during long operations.

journal(string message, dict<string,string> fields = {}): void

Sends a structured entry to the systemd journal. message becomes the MESSAGE field. Each key/value pair in fields is sent as an additional KEY=value field. Standard journald field names include PRIORITY (syslog numerics: "3" = error, "6" = info), SYSLOG_IDENTIFIER, and UNIT. Custom field names are allowed and are searchable with journalctl.

Service readiness sequence

import clib.systemd as systemd;
import io;

/* ... initialise database connections, load config ... */

let delivered = systemd.ready();
io.println("ready notification delivered: ${delivered}");
systemd.status("serving");

Updating the status line during long operations:

systemd.status("running migration 3 of 7");
/* ... */
systemd.status("migration complete");

Structured journal logging

import clib.systemd as systemd;

systemd.journal("request handled", {
    "PRIORITY":            "6",
    "SYSLOG_IDENTIFIER":   "myapp",
    "REQUEST_ID":          requestId,
    "HTTP_STATUS":         "200"
});

Query the journal with matching fields:

journalctl SYSLOG_IDENTIFIER=myapp HTTP_STATUS=200

Watchdog example

import clib.systemd as systemd;
import async;

/* Ping the watchdog every 10 seconds from a background task. */
async.run(func(): void {
    while (true) {
        systemd.watchdog();
        async.sleep(10000);
    }
});

Set WatchdogSec=30 in the [Service] section of the unit file and call watchdog() at most every 15 seconds.

Thread safety

sd_notify and sd_journal_sendv are thread-safe in libsystemd. All five functions in this module are safe to call concurrently from multiple async tasks.