Fra magasinets tema til projektpraksis
Passende service- og tekniske sider til artiklen
Video-Botschaft
Linux-Services med Delphi i produktiv drift
Kurze Einordnung, warum Delphi-basierte Linux-Services im Betrieb nicht an der Fachlogik scheitern, sondern an Logging, systemd-Integration, Updates und definiertem Fehlerverhalten – und welche Perspektive für robuste Nacht-3-Uhr-Setups zählt.
Video mit KI erstellt
Transkript anzeigen
Guten Tag. Die meisten Service-Probleme sind keine Programmfehler.
Es sind Betriebsfehler. Im Beitrag „Linux-Services mit Delphi im produktiven Betrieb“ geht es genau darum: Hintergrunddienste sind nur dann hilfreich, wenn man sie wie einen Produktbestandteil betreibt.
In der Praxis scheitert es oft an Basics: Wie startet und stoppt der Dienst sauber? Unter Linux übernimmt das meist systemd, also die Service-Steuerung fürs System.
Wie sieht Logging aus, sodass man nachts um drei Ursache statt Vermutung hat? Und was passiert bei Neustarts, Netzproblemen oder doppelten Jobs?
Die Kernaussage ist nüchtern: Fachlogik reicht nicht. Zustände, Updates, Rechte und Wiederanlauf müssen geplant sein.
Wenn Sie dazu Fragen haben, klären wir sie gern entlang Ihres Betriebsmodells.
Baggrundstjenester er i mange virksomhedsapplikationer den stille produktivitetsløft: dataimporter, eksporter, fil- og EDI-behandling, synkronisering med ERP/DMS/CRM, tidsstyrede workflows, notifikationer eller levering af tekniske grænseflader. I praksis afgør ikke den rene forretningsfunktion succesen, men spørgsmålet: Kan tjenesten drives, opdateres, overvåges og kontrolleret gendannes ved fejl?
Netop her er et nøgternt blik på Linux-tjenester med Delphi nyttigt. Delphi udgør i mange organisationer allerede kernen i forretningslogikken. Hvis denne logik fornuftigt kan genbruges på serversiden, opstår en konsistent samlet arkitektur: forretningsregler implementeres ikke dobbelt, interfaces forbliver stabile, og teams arbejder med etablerede værktøjer. Samtidig bringer Linux i serververdenen velafprøvede byggesten til drift, automatisering og sikkerhed.
Det afgørende punkt: En Linux-tjeneste er ikke et „lille hjælpeprogram“, man starter ved siden af. Den er en del af produktet med driftsansvar. Dette indlæg viser konkret, hvordan Delphi-baserede Linux-tjenester i produktion kan gøres robuste: fra proces- og tilstandsmodel over systemd-integration, logging, deployment og opdateringer til monitoring, dataadgang, sikkerhed og typiske fejltilstande. Målet er et setup, der fungerer i hverdagen – også kl. 03:00 om natten.
Hvornår Delphi-tjenester under Linux giver mening
En Delphi-Linux-tjeneste er oplagt, når ét eller flere af følgende mønstre gør sig gældende:
- Eksisterende Delphi-forretningslogik skal bruges på serversiden (f.eks. valideringer, beregninger, regelsæt, import/eksport-parsere).
- Baggrundsbehandling er en integreret del af applikationen (f.eks. PDF-/rapportpipelines, job-køer, batch-behandling).
- Integrationsbelastning stiger: mange systemer, mange interfaces, mange formater; pålidelig gentagbarhed (idempotens) bliver vigtig.
- Modernisering uden at starte forfra: dele af logikken udlægges til tjenester, mens desktop-klienten gradvis slankes.
- REST-Server & tjenester bør tænkes sammen: samme kode-standard, samme logging/monitoring, samme rollout-processer.
Mindre egnet er en Delphi-tjeneste under Linux, hvis et team slet ingen Delphi-kompetence har og en standardiseret platform (f.eks. et eksisterende Java/.NET-økosystem) er strikt påkrævet. Så er problemet ikke Delphi, men den organisatoriske indlejring. I mange virksomheder er Delphi dog en eksisterende værdi, som kan genbruges stabilt i services – så længe arkitektur og drift planlægges grundigt.
Arkitekturgrundlag: procesmodel, tilstande, ansvarsfordeling
En produktiv tjeneste fejler sjældent på selve „hovedfunktionen“. Oftere fejler den på uklare tilstande: Hvad sker der ved netværksudfald? Hvordan opfører tjenesten sig ved database-failover? Bliver et job behandlet to gange? Er adfærden ved SIGTERM defineret? Netop derfor har hver tjeneste brug for en klar proces- og tilstandsmodel.
Servicetyper: Always-on vs. Worker vs. Job-Runner
I B2B-miljøer er tre grundtyper udbredte:
- Altid kørende daemon: en permanent kørende proces, f.eks. listener, queue-consumer, event-dispatcher, WebSocket-/push-komponent.
- Worker-pool: flere instanser, der parallelt behandler jobs fra en kø. Skalering sker via antal processer.
- Job-Runner (Timer): starter periodisk, udfører opgaver og afslutter igen. Under Linux er dette ofte bedre løst med systemd-timers/cron end med egne scheduler-tråde.
Delphi kan implementere alle tre mønstre. For driften er det dog afgørende, at mønsteret vælges bevidst. En „always-on“-proces, der reelt kun gør noget hvert 15. minut, medfører unødig kompleksitet (memory leaks opdages senere, idle-tilstande håndteres ikke ordentligt). Omvendt kan en ren job-runner være uhensigtsmæssig, hvis lav latenstid er krævet.
Idempotenz und Wiederanlauf: der Kern produktiver Robustheit
Produktiv drift betyder: tjenester genstartes, deployments kører, netværk er midlertidigt ustabile, databaser har vedligeholdelsesvinduer, og jobs kommer dobbelt. Derfor er idempotens (flere udførsler uden sideeffekter) ved importer, eksporter og integrationer et grundprincip.
Praktisk betyder det:
- Hvert job har en entydig job-ID og en status (queued, running, succeeded, failed, dead-letter).
- Sideeffekter (f.eks. „faktura sendt“) registreres med et dedikeret bevis, ikke udledt implicit fra logs.
- Retry-strategier er kontrollerede: backoff, maks. forsøg, klare afbrudskriterier, dead-letter-kø.
Den, der indfører idempotens konsekvent, vinder markant i drift: En genstart er så ikke en krise, men en standardprocedure.
systemd als Betriebsfundament: Start, Stop, Restart, Limits
Under Linux er systemd i de fleste distributioner det centrale værktøj til at drive services professionelt. For Delphi-tjenester er systemd ikke blot et startscript, men en del af stabilitetsarkitekturen. En veldefineret unit-fil er ofte forskellen mellem „kører en eller anden måde“ og „kan drives professionelt“.
Wichtige Parameter im Unit-File
For typiske Delphi-daemons er følgende aspekter relevante:
- Restart-Policy: f.eks. Restart=on-failure eller always, kombineret med RestartSec for at undgå crash-loops.
- TimeoutStopSec og KillSignal: muliggør ordnet shutdown (flush af køer, korrekt luk af DB-transaktioner).
- User/Group: services bør sjældent køre som root; principle of least privilege.
- WorkingDirectory og Environment: reproducerbare stier og miljøer i stedet for implicitte antagelser.
- LimitNOFILE og ressourcelimits: vigtigt ved mange samtidige forbindelser/filer.
- Logging-tilknytning: StandardOutput/StandardError til journald, eventuelt suppleret med forwarding til centralt log-system.
Især restart-politikker skal vælges med omtanke. En proces, der stopper med det samme pga. en konfigurationsfejl, bør ikke genstartes i en uendelig løkke og flodle systemet. I sådanne tilfælde er klare exit-codes og et „fail fast“ med tydelig fejlnoteringsmelding hensigtsmæssigt.
Graceful Shutdown in Delphi: SIGTERM ist kein Detail
I Linux-drift afsluttes en tjeneste typisk via SIGTERM. En Delphi-tjeneste bør behandle dette som en normal tilstand: ingen abrupt afbrydelse, men ordnet nedlukning.
Det omfatter i praksis:
- Sætte stop-flag, acceptere ikke nye jobs.
- Afslutte kørende jobs eller afbryde dem kontrolleret (afhængigt af semantik).
- Commit/rollback af transaktioner, lukke forbindelser korrekt.
- Persistér vigtige statusinformationer (f.eks. „Job X afbrudt, retry mulig“).
En tjeneste, der „dør hårdt“ ved SIGTERM, skaber inkonsistenser og gør vedligehold vanskeligere.
Konfiguration: reproducerbar, versionsstyrbar, sikker
Mange produktionsproblemer er i bund og grund konfigurationsproblemer: forkert DB-host, forkerte credentials, manglende stier, divergerende timeout-værdier mellem miljøer. Derfor er konfiguration ikke bare „en INI-fil“, men et koncept.
Konfigurationsquellen und Prioritäten
Et flerlaget model har vist sig robust:
- Default-konfiguration i koden (sikker baseline, fornuftige timeouts).
- Filbaseret konfiguration (f.eks. INI/JSON/YAML), som kan rulles ud versionsstyret.
- Environment-variabler til secrets og miljøspecifikke værdier (container/CI-nært, ingen secrets i repo).
Vigtigt er en klar prioritering (f.eks. env overskriver fil overskriver default) og en start-check, der validerer konfigurationen: obligatoriske felter, tilgængelighed, filrettigheder, minimale værdier.
Secrets: nicht im Klartext, nicht in Logs
I B2B-miljøer er database-adgangskoder, API-tokens, certifikater og private keys blandt de vigtigste driftsaktiver. Minimale standarder:
- Secrets ikke i Git og ikke i deployede konfigurationsfiler i klartekst, når det kan undgås.
- Læserettigheder for konfig/secrets kun for service-user.
- Log-udskrifter skal konsekvent maskere secrets (også ved undtagelser).
Om man bruger et Vault-system eller klassiske deployments med restriktive rettigheder: afgørende er, at håndteringen af secrets er systematisk.
Logging: vom „Fehlertext“ zur betrieblichen Diagnosefähigkeit
En produktiv Linux-tjeneste er kun så god som sin diagnoseevne. „Der var en fejl“ hjælper ikke. Ved incidenter skal drift og udvikling kunne reproducere: Hvad var input? Hvilken version kørte? I hvilket trin opstod fejlen? Var det en transient fejl eller et dataproblem?
Strukturiertes Logging und Korrelations-IDs
For tjenester med interfaces (REST, MQ, fil-importer) er to ting centrale:
- Struktureret logging (key-value, JSON-lignende): service, version, env, job_id, customer_id (hvis tilladt), duration_ms, result.
- Korrelations-ID: en ID, der føres gennem komponenterne (f.eks. fra REST-requesten ind i worker-jobbet).
Med disse kan produktionsfejl ikke bare findes, men også afgrænses: Rammer det alle kunder? Kun én datakilde? Kun en version? Kun en instans?
Log-Level, Noise und operative Signale
Et hyppigt anti-mønster er for mange logs uden signal: megabytes af „Processing…“ ved hvert poll. I stedet:
- INFO: relevante tilstandsændringer (start, stop, konfig indlæst, job startet/afsluttet).
- WARNING: forventede afvigelser (retry, transient netværksfejl, timeouts).
- ERROR: uventet, kræver manuel handling.
- DEBUG: aktiverbart målrettet og tidsbegrænset.
Specielt i systemd/journald-miljøer er det fornuftigt at planlægge logrotation og retention. Uden retention-koncept gemmes logs enten for kort (ingen diagnose) eller de fylder disk (driftsproblem).
Monitoring und Health: nicht nur „läuft“ – sondern „liefert“
En proces kan køre og alligevel være fagligt død (sidder i deadlock, venter på IO eller behandler ikke længere jobs). Produktionsmodenhed betyder: monitoring kontrollerer ikke bare processtatus, men tjenestens helbred.
Health Checks: Liveness, Readiness, Business-Checks
For Delphi-tjenester giver tre niveauer mening:
- Liveness: processen er i live (systemd status, watchdog, enkel ping-endpoint).
- Readiness: tjenesten er klar (DB-forbindelse mulig, konfiguration valid, afhængige systemer tilgængelige).
- Business-Check: behandler tjenesten faktisk? f.eks. „sidste succesfulde job < 10 minutter“ eller „kø-længde < tærskel“.
Business-niveauet er ofte det vigtigste i B2B-drift, fordi det måler reel værdiskabelse.
Metriken: Laufzeiten, Fehlerraten, Backlog
Når services vokser, er logs alene ikke længere nok. Metrikker hjælper med at se trends:
- Gennemstrømning (jobs/min), gennemsnitlig jobvarighed, p95/p99-tider.
- Retry-rate, fejlrater efter fejlklasse (netværk, data, auth).
- Kø-backlog, ventetider, dead-letter-tæller.
Selv uden et komplekst observability-stack kan simple eksporter (f.eks. via et internt HTTP-endpoint eller log-baseret parsing) levere meget. Vigtigt er konsekvent definition af metrics og tærskler.
Dataadgang og transaktioner: FireDAC, Connection-Handling, Pooling
Mange Delphi-tjenester er databasecentrerede. Under Linux organiseres adgangen i Delphi typisk via BDE-afløsning med native binding og native client-biblioteker. For produktionsmodenhed er det mindre de „rigtige drivere“ end connection- og transaktionsmodellen, der tæller.
Connection-Lifecycle: kurzlebig vs. langlebig
For background-jobs er en udbredt praksis:
- Åbn en connection per job eller job-batch, arbejd og luk (robust ved netværksforstyrrelser).
- Ved højfrekvente jobs evt. connection-pooling, men kun med et ordentligt reset mellem jobs.
Langevarende forbindelser kan fungere, men bryder lettere sammen ved netværksafbrydelser eller DB-failovers og ender i sværere diagnostiske tilstande. Kortvarige forbindelser er ofte den mere robuste default-strategi – med passende timeouts og retries.
Transaktionsgrenzen und Sperrverhalten
Produktionsproblemer opstår ofte ved for store transaktioner: lange locks, blokerede tabeller, „alt hænger“. Bedre er:
- Tilpas transaktioner efter faglige enheder (f.eks. „en importpost“ eller „et dokument“).
- Persistér mellemliggende resultater for at muliggøre genkørsel.
- Klassificér fejl tydeligt: datafejl (ikke retry), netfejl (retry), sideeffekt allerede udført (behandles idempotent).
Især ved parallelle workers er låse- og deadlock-adfærd et designproblem – ikke kun et DBA-emne.
Deployment und Updates: reproduzierbar, rückrollbar, mit minimalem Risiko
En tjeneste er aldrig „færdig“; den opdateres. Derfor er deployment ikke efterarbejde, men en del af løsningen. I produktion tæller tre egenskaber: reproducerbarhed, rollback-evne og lav nedetid.
Versionierung und Artefakte
God praksis er:
- Hvert build har en entydig versionsnummer (SemVer eller build-ID) og skriver det i log ved opstart.
- Artefakter er immutable: samme version bygges ikke „på ny“ og overskrives ikke.
- Afhængigheder (f.eks. native libraries) er en del af deployment eller klart dokumenterede.
Det mindsker risikoen for, at „version X“ i virkeligheden ser lidt forskellig ud per server.
Update-Strategien: Rolling, Blue/Green, Stop/Start
Hvilken strategi der passer afhænger af mønsteret:
- Stop/Start: til job-runners eller ikke-kritiske services; simpelt, men med kort nedetid.
- Rolling Update: flere instanser genstartes én ad gangen; kø-baserede systemer egner sig godt.
- Blue/Green: to separate miljøer, switchover via load-balancer; større indsats, minimal risiko.
Vigtigt: Et update er kun „sikkert“, hvis tjenesten ved start forventer en kompatibel database-/schema-version eller migrationer kører kontrolleret. Schema-ændringer er et selvstændigt rollout-trin med plan (for- og bagudkompatibelt eller med vedligeholdelsesvindue).
Sicherheit und Betriebshärtung: kleine Maßnahmen, große Wirkung
Linux-tjenester er ofte tæt på data, interfaces og credentials. Derfor er hærdning ikke luksus. Få standardtiltag reducerer risiko markant.
Least Privilege und Dateirechte
- Egen service-user uden shell-login, minimale gruppetilladelser.
- Konfigurations- og secret-filer læsbart kun for denne user.
- Skrivetilladelser kun hvor nødvendigt (f.eks. working-directory, spool, temp).
Netzwerkgrenzen und Port-Management
Hvis en Delphi-tjeneste åbner porte (f.eks. som REST-Server), bør følgende gælde:
- Bind til interne interfaces, hvis ekstern tilgængelighed ikke er nødvendig.
- Firewall-regler og segmenterede netværk frem for „åbent i LAN“.
- TLS-termination planlagt korrekt (reverse proxy, cert-rotation), afhængig af miljøet.
Også internt bør tjenester ikke blot „stole“ på, at kun gode klienter kalder. Autentifikation og autorisation er del af designet.
Typiske Fehlerbilder in der Praxis – und wie man sie vermeidet
I produktion er det ofte tilbagevendende mønstre, der koster tid. Nogle typiske tilfælde og modforanstaltninger:
„Der Service läuft, aber verarbeitet nichts mehr“
- Årsag: deadlock, blokerende IO, stilfærdigt reconnect-problem.
- Modforanstaltning: timeouts overalt; watchdog/business-health-check; worker-arkitektur frem for single-thread; fail-fast ved ødelagt afhængighed.
„Nach einem Update sind Jobs doppelt“
- Årsag: manglende idempotens, ingen dedikeret job-tabel, sideeffekter ikke atomiske.
- Modforanstaltning: job-status i DB, entydige constraints, outbox-/inbox-mønster, deduplikerbare events.
„Logs helfen nicht – nur Stacktraces ohne Kontext“
- Årsag: ustruktureret logging, ingen korrelations-ID, intet job-kontekst.
- Modforanstaltning: strukturerede logfelter, job-ID, input-kilde, varighed, resultat, fejlklasse.
„Der Service bricht bei Last zusammen“
- Årsag: ukontrolleret parallelitet, manglende backpressure, for mange DB-forbindelser, for store transaktioner.
- Modforanstaltning: worker-limits, kø-længder, connection-limits, små transaktioner, buffere og retries.
Sammenspil med REST-Servern und eksisterende Unternehmenssoftware
I mange arkitekturer findes ikke „én enkelt tjeneste“, men et paket af REST-server, background-workers og klienter. I Delphi-projekter er det ofte fornuftigt at holde fælles forretningslogik i klare moduler, mens transport- og driftsspecifikke dele holdes adskilt.
Schichten sauber trennen (fachlich und technisch)
En pragmatisk struktur:
- Domain/Forretningslogik: regler, validering, beregninger, use-cases.
- Infrastruktur: DB-adgang, filsystem, HTTP-klienter, messaging.
- Adapter: REST-endpoints, service-loop, CLI-runner, systemd-nær startlogik.
Denne adskillelse er ikke akademisk. Den gør det muligt at genbruge samme forretningslogik i REST-serveren og i workeren, mens driftsaspekter (timeouts, retries, logging, health) implementeres konsekvent.
Multiplattform-Gedanke: Delphi als einheitliche Codebasis
Hvis virksomheder bruger Delphi til Windows-klienter, kan en Linux-tjeneste være næste logiske skridt: samme sprog, lignende biblioteker, ens build-pipelines. Gevinsten opstår dog kun, hvis man bevidst respekterer platformgrænser (stier, case-sensitivity, locale/encoding, service-user-rettigheder, deployment-konventioner). Multiplatform i drift er altid „detalje-arbejde“ – derfor bør det planlægges tidligt.
Praxischeckliste: Was ein produktiver Delphi-Linux-Service mindestens braucht
- systemd-unit med fornuftige restart-/timeout-regler, egen service-user, definerede stier.
- Graceful shutdown (SIGTERM), ingen datainkonsistenser ved stop.
- Konfigurationsmodel med validering, secrets sikre, ingen secrets i logs.
- Struktureret logging med version, job-ID, korrelations-ID, varighed, fejlklasse.
- Health checks (mindst readiness + business-check) og definerede metrics.
- Idempotent job-behandling, retry/backoff, dead-letter-koncept.
- Deployment med klar versionering, rollback-strategi, planbare schema-migrationer.
- Ressource- og belastningskoncept: parallelitet, limits, timeouts, connection-håndtering.
Fazit: Delphi unter Linux ist kein Spezialfall – wenn Betrieb mitgedacht wird
Linux-tjenester med Delphi er i drift en meget solid mulighed, hvis de behandles som fuldgyldige systemkomponenter: med klar arkitektur, ordentlig systemd-integration, robust fejl- og tilstandsmodel, gennemskuelig logging, monitoring og reproducerbart deployment. Den tekniske implementering er sjældent den største risiko; risikoen ligger i de driftsdetaljer, der afklares for sent.
Den, der planlægger disse detaljer fra starten, får et vedligeholdelsesvenligt tjenestelandskab, som genbruger forretningslogik konsistent, håndterer integrationer stabilt og kan drives pålideligt i dagligdagen – inklusive opdateringer, genstarter og fejl.
Hvis I vil vurdere, hvordan jeres eksisterende Delphi-forretningslogik kan overføres til Linux-tjenester, workere og REST-servere (inkl. drift- og deploymentkoncept), gennemgår vi gerne randbetingelserne struktureret i en teknisk indledende samtale: Kontakt.
Næste trin
Når emnet bliver til et reelt projekt, bør arkitektur, eksisterende systemer og drift tidligt vurderes samlet.
Vi støtter ikke kun ved enkeltspørsmål, men også når kildekodeudsnit, legacy-komponenter eller portalidéer skal udvikles til et robust virksomhedsprojekt.
- Eksisterende tilstand, målbillede og tekniske risici vurderes samlet.
- REST, dataadgang, portaler og udrulning bliver ikke udskudt som efterfølgende opgaver.
- De ser tidligt, hvilken vej der er økonomisk og driftsmæssigt bæredygtig.