Gå til hovedindhold

Enable-linger var en lappeløsning — her er alternativerne

Indsendt af Lennart den
Enable-linger var en lappeløsning — her er alternativerne

I forrige indlæg fortalte jeg om de to dage, hvor jeg gik rundt og troede, jeg havde et kørende system — men i virkeligheden havde et system, der hang i en tråd, jeg selv holdt i. Løsningen blev sudo loginctl enable-linger $USER, som tillader, at en brugers baggrundsprocesser overlever, at brugeren logger ud.

Det virkede. Men jo længere jeg kiggede på det, jo tydeligere blev det, at linger ikke er den rigtige løsning. Den er en lappeløsning. Den besvarer et spørgsmål om min personlige session — ikke et spørgsmål om drift.

Her er hvorfor, og her er hvad man bør gøre i stedet.

Hvad linger faktisk gør

enable-linger siger til systemet: "Hold den her brugers tjenester kørende, også når brugeren ikke er logget ind." Det er stadig brugerens tjenester. De er bundet til en personlig konto, startet som en del af en login-model, og de lever, fordi vi har bedt systemet om at lade som om, brugeren altid er der.

Det fungerer på en bærbar eller en server, hvor man selv er den eneste, der rører ved tingene. Men det betyder, at automatiseringen er bundet til en person. Forsvinder kontoen — eller forsvinder personen — er det uklart, hvem der ejer den proces.

For en virksomhed er det netop dér, problemet ligger. Et system, der kun lever, fordi Lennarts bruger har linger slået til, er ikke infrastruktur. Det er et kæledyr.

Alternativ 1: En rigtig systemtjeneste

Den kanoniske løsning er at lade processen være en systemtjeneste i stedet for en brugertjeneste. Den startes ved boot, ejes af root eller en dedikeret servicebruger og er fuldstændig uafhængig af, om nogen overhovedet er logget ind.

En lille unit-fil under /etc/systemd/system/min-pipeline.service:

[Unit]
Description=Nyhedspipeline til folkets.dk
After=network-online.target

[Service]
ExecStart=/opt/pipeline/run.sh
Restart=always
RestartSec=10
User=pipeline

[Install]
WantedBy=multi-user.target

Slå den til:

sudo systemctl enable --now min-pipeline.service

Forskellen er ikke kosmetisk. Med Restart=always rejser tjenesten sig selv efter et nedbrud. Den starter ved boot — også klokken tre om natten efter en strømafbrydelse. Den logger til journald, så journalctl -u min-pipeline viser præcis, hvad der skete. Og den behøver ikke linger, fordi den aldrig var bundet til en login-session til at begynde med.

Alternativ 2: En timer, ikke en dæmon

Her er det spørgsmål, jeg burde have stillet først: skal processen overhovedet køre hele tiden?

En nyhedspipeline, der henter nyt hver time, behøver ikke at være en proces, der kører 24 timer i døgnet og venter. Den kan være en timer, der vågner, gør sit arbejde og lægger sig til at sove igen.

min-pipeline.timer:

[Unit]
Description=Kør nyhedspipeline hver time

[Timer]
OnCalendar=hourly
Persistent=true

[Install]
WantedBy=timers.target

Det smukke ved Persistent=true: hvis maskinen var slukket, da kørslen skulle have fundet sted, kører den, så snart maskinen er oppe igen. En proces, der ikke kører hele tiden, kan heller ikke crashe hele tiden. Mindre overflade, færre fejl. (Den gammeldags udgave er cron — den virker fint, men giver dig ikke journald-logning og afhængighedsstyring.)

Alternativ 3: En container med restart-politik

Kører automatiseringen i en container, flytter ansvaret for at holde den i live til container-runtimet:

docker run --restart=always min-pipeline

Eller i docker-compose.yml:

services:
  pipeline:
    image: min-pipeline
    restart: unless-stopped

Her bliver Docker selv supervisoren — og Docker er en systemtjeneste, der starter ved boot. Det fungerer godt, hvis du allerede arbejder med containere. Men bemærk: det flytter blot problemet et lag ned. Er Docker ikke slået til ved boot (systemctl enable docker), er du lige vidt. Og du har nu to ting at holde øje med i stedet for én.

Det, man skal lade være med

De fristende genveje er præcis det, der bragte mig i problemer i første omgang:

  • nohup kommando & — overlever logout, men ikke en genstart, og rejser sig ikke efter et nedbrud.
  • tmux eller screen — holder en session i live, men det er stadig en tråd, du holder i. Lukker sessionen, dør alt.
  • & alene — dør i samme sekund, du logger ud. Det var her, jeg startede.

De har alle den samme svaghed: de forveksler "kører lige nu" med "kører pålideligt".

Pointen er ikke kommandoen

Ligesom sidst er pointen ikke den enkelte kommando. Det er spørgsmålet bagved: hvad skal eje den her proces?

enable-linger besvarer et spørgsmål om en personlig maskine: hold mine ting kørende, når jeg går. En systemtjeneste besvarer et spørgsmål om drift: dette er en del af infrastrukturen, og den lever, uanset hvem der er logget ind, og om jeg overhovedet er her.

For en lille virksomhed, der begynder at bygge automatisering, er det den vigtigste skelnen. Forskellen mellem en lappeløsning og en tjeneste er forskellen mellem et system, der hænger i en enkelt persons login — og et system, der bare kører.