Net-Base Tímarit

02.08.2026

Windows-þjónusta í Delphi: Rétt útfærsla á hreinni lokun með TEvent og Stop-Timeout

Þegar Windows-þjónusta hangar við stöðvun er það sjaldan tilviljun: yfirleitt stíflast þræðir, I/O eða svefnlykkjur sem hafa enga lokunarleið. Þessi hagnýta grein sýnir hvernig þú í Delphi notar TEvent til að innleiða hreinan, stýrðan graceful shutdown og hvernig á að meðhöndla Stop-Timeouts rétt.

02.08.2026

Frá tímaritsþema til verkefnaframkvæmdar

Viðeigandi þjónustu- og tæknisíður fyrir greinina

Ein Windows Service in Delphi wirkt im Alltag oft unspektakulär: läuft im Hintergrund, verarbeitet Jobs, schreibt Logs, spricht Datenbanken oder REST-APIs an. Bis jemand „Dienst beenden“ klickt – oder ein Patch-Reboot ansteht – und der Service nicht sauber stoppt. Dann zeigt die Dienste-Konsole minutenlang „Wird beendet…“, der Service hängt im Stop Pending-Status, und im schlimmsten Fall wird der Prozess hart beendet. Genau hier lohnt es sich, Windows Service in Delphi Graceful Shutdown als bewusstes Architekturthema zu behandeln: mit einem klaren Shutdown-Signal, definierten Timeouts und Threads, die wirklich reagieren.

Í þessari grein er ekki fjallað um innri virkni frameworks, heldur um hagnýtt mynstur: TEvent sem stoppsignal (kjarna-nálægt samstillingarhlutverk úr System.SyncObjs), saman með Stop-Timeout-stefnu sem tekur bæði Windows Service Control Manager (SCM, það er Windows-hlutinn sem ræður upphafi/stöðvun þjónusta) og eigin vinnuþræði þína með. Þarna fylgja dæmigerðir jaðartilvik, leiðir til útflettingar og umræðan um hvenær slíkur viðbótarhugbúnaður skiptir raunverulega máli.

Windows Service in Delphi Graceful Shutdown in der Praxis

Algengasta orsökin er einföld: Þjónustan á að minnsta kosti einn þræði sem situr í blokkandi aðgerð og þekkir engan hættustigleið. Klassísk dæmi:

  • Polling-Schleifen mit Sleep: „while not Terminated do Sleep(1000)“. Beim Stop kommt das Signal an, aber der Thread reagiert erst nach bis zu 1 Sekunde (oder 30 Sekunden…).
  • Blockierende I/O: Datenbank-Calls, HTTP-Requests, Named Pipes, Filesystem-Waits – alles, was „einfach wartet“, ohne auf ein Stop-Signal zu achten.
  • Queue-Consumer ohne Wakeup: Ein Worker wartet auf eine Queue, aber beim Stop wird er nicht geweckt, um auszusteigen.
  • Lock-Reihenfolge/Deadlocks: Beim Stop wird „Cleanup“ gemacht, während andere Threads noch Locks halten. Das tritt gern nur im Stop-Pfad auf, weil die Reihenfolge dort anders ist als im Normalbetrieb.

Der Windows SCM erwartet, dass ein Service auf ein Stop-Kommando zügig reagiert und seinen Status fortlaufend meldet (über SetServiceStatus; Delphi kapselt das in der Service-Komponente). Wenn du zwar ein Stop-Ereignis annimmst, aber deine Threads nicht sauber runterfährst, bleibt der Prozess lebendig – und Windows entscheidet irgendwann, dass es „zu lange dauert“. Das Ergebnis ist dann entweder ein harter Abbruch oder ein Service, der in einer unklaren Zwischenwelt hängenbleibt.

Grundprinzip: Ein Stop-Signal, das jeder Worker versteht

Abstrakte Grafik: Worker-Threads warten auf Work oder Stop-Event und beenden geordnet
Þegar vinnuþræðir bíða eftir „vinna eða stöðvun“, lækkar stopplatensían án polling.

Ein Graceful Shutdown funktioniert nur, wenn du ein Signal hast, das:

  • von allen relevanten Threads beobachtet werden kann,
  • virkar einnig úr blokkerandi biðástandi,
  • í Stop-slóðinni determinístískt er (engin „kann vera að hann komi út einhvern tíma“-von),
  • hefð skýra Timeout-strategíu.

Í Delphi er TEvent mjög hentugt verkfæri fyrir þetta: Event-objekt sem er innanhúss útfært með Windows-handleum (samanburðarvert við CreateEvent/SetEvent). Þú getur notað það sem „Stop requested“-merki. Hver Worker bíður þá ekki einfaldlega blindur, heldur bíður „eftir vinnu eða eftir Stop“.

Rétt val á TEvent: Manual Reset vs. Auto Reset

Fyrir stoppskilaboð viltu yfirleitt Manual Reset (handvirkt endurstillanlegt): Þegar það er sett helst Eventið „signaled“ þar til þú endurstillir það. Þetta tryggir að allir þræðir sem síðar fara í biðástand skynji stoppskilaboðin. Auto Reset væri hér áhættusamt, því það endurstillir merkið sjálfkrafa eftir einn biðjandi þræði og aðrir þræðir gætu misst af stoppskilaboðunum.

Delphi-þjónustulífsferill: Hvar Stop raunverulega skilar sér

Ein Delphi-Windows- und Linux-Services byggir yfirleitt á TService (VCL/RTL). SCM sendir skipanir (Start, Stop, Pause, Continue). Delphi kallar þá á viðeigandi atburði/aðferðir (fer eftir sniðmáti, t.d. OnStart, OnStop, OnExecute).

Mikilvægt fyrir arkitektúrinn:

  • OnStop er ekki staður fyrir langa bið án stöðufréttinga. Þetta er staðurinn þar sem þú ræsir lokunarferlið og bíður síðan stýrt – með timeout.
  • OnExecute er oft lykkja. Ef þú vinnur þar „endalaust“ þarf lykkjan að bregðast við Stop-skilaboði.
  • Worker-Threads (TThread eða Thread-Pools) verða að bregðast við sama Stop-skilaboðinu, annars er þjónustan rökvísilega stöðvuð en ekki lokið í raun.

Skýrt mynstur: Stop-Event + Join der Worker + harður Fallback

Þetta hagnýta mynstur samanstendur af fjórum skrefum:

  1. Beiðja um Stop: Setja Stop-Event; taka ekki við nýjum verkefnum.
  2. Vekja upp: Ef Worker bíða á raðir eða í Sleep verða þeir að geta „vaknað“ (t.d. með Event/Queue-merki).
  3. Skipulega ljúka: Worker ljúka lykkjum sínum, loka auðlindum (DB-tengingar, skrár, handles) og skila „lokið“.
  4. Timeout og Fallback: Ef ekki allt lýkur tímanlega verður þú að taka ákvörðun: bíða áfram (með stöðufréttingu) eða hætta á stjórnaðan hátt eða loka hörðum hætti (eftir áhættu).

Kjarninn er: enginn þráður má eingöngu bíða með tíma (Sleep) eða eingöngu blokkerast á I/O án þess að taka samhliða tillit til Stop-skilaboða. Í staðinn notar þú biðaföll sem taka marga boðflutninga í reikninginn (t.d. „Stop-Event oder Work-Event“), eða þú umbúðir I/O með timeoutum auk Stop-eftirlits.

Hugsa rétt um Stop-Timeout: SCM-Timeout vs. eigið Shutdown-Timeout

  • SCM-vænting: Windows væntir þess að þú skráir reglulega framvindu þegar þú ert í stöðu SERVICE_STOP_PENDING. Annars lítur það út eins og þú hafir frosið. Delphi sér að hluta til um þetta, en um leið og þú sjálfur lokar lengur, þarftu stefnu til að halda áfram að senda stöðuuppfærslur (eða til að halda stoppphase stuttri).
  • Þinn eigin shutdown‑timeout: Þú skilgreinir t.d. „Við gefum okkur 20 sekúndur til að ljúka gangandi verkefnum á hreinan hátt, síðan hættum við.“ Þetta er arkitektúrleg ákvörðun: gagna‑samræmi vs. endurræsingaþvingun vs. rekstrarkröfur.

Í framkvæmd þýðir þetta: þjónustan þín á að komast fljótt í ástand þar sem hún byrjar ekki á nýjum vinnueiningum, og síðan bíðst eftir að gangandi vinna ljúki – en ekki að eilífu. Þessi biðfasi ætti að keyra í stuttum lotum, svo þú getir brugðist við og, ef þörf krefur, skráð atburði.

Hve langan tíma má stöðvun taka?

Það er engin töfratala sem passar alltaf. Fyrir marga business‑þjónustu er markgildi um 5–30 sekúndur raunhæft: nægur tími fyrir „in‑flight“ gögn, en stutt nægjanlegt fyrir patch‑glugga. Ef þú þarft reglulega lengri tíma bendir það oft til að þú vinnir of stórar einingar í einu eða að ytri háðir þættir (DB/HTTP) gangi án timeout.

Innleiðing með TEvent: uppbygging sem helst stöðug í rekstri

Gagnreynd uppsetning í Delphi‑þjónustu lítur svona út (án þess að fara í ramma‑smáatriði):

  • Eitt Stop‑Event (TEvent, Manual Reset), sem er stillt við stöðvun.
  • Einn eða fleiri vinnuþræðir, sem í meginlykkju sinni athuga reglulega fyrir Stop.
  • Valfrjálst Work‑Event eða biðröð (queue) sem merkir vinnu. Vinnuþræðir bíða þá eftir „Work eða Stop“.
  • Ein shutdown‑fasa, sem „joined“ vinnuþræði (þ.e. bíður þar til þeir ljúka), en með timeout.

Það sem skiptir máli er ekki hvort þú notar TThread, omnithreadlibrary eða eigið pool, heldur að vinnuþræðirnir þínir keyri ekki „blindir“. Vinnu‑lykkja ætti að vera byggð upp svona: Bið eftir atburði(um) → vinna í litlum köflum → athuga Stop á milli köflanna → losa auðlindir á hreinan hátt.

Gildra: Terminate einn sér dugar ekki

Margir Delphi‑þræðir eru „afbrotnaðir“ með Terminate. Það er þó aðeins merki. Ef þræðir sitja í blokkerandi API‑kalli gerist í fyrstu ekkert. Þess vegna er sértakt Stop‑Event svo gagnlegt: þú getur fellt það inn í biðköll og kallað fram vakningar markvisst.

Gildra: FreeOnTerminate í þjónustusamhengi

Í þjónustum sést oft FreeOnTerminate := True. Þetta getur virkað, en gerir lokun erfiðari að stjórna, því þú hefur þá oft ekki hreina tilvísun til að bíða eftir þráðarenda og skrá villuástand. Fyrir stýrða stopplógík er yfirleitt stöðugra að eiga þræðina skýrt og bíða á ákveðinn hátt og losa þá í lokun.

Blokkerandi aðgerðir: hvernig gera þær stoppanlegar

Troubleshooting-Szene: Netzwerkverbindung als Ursache für blockierende Calls und Timeouts
Lásandi I/O án timeout er algengasta ástæðan fyrir að þjónusta festist við stöðvun.

Erfiði hlutiinn er ekki atburðurinn sjálfur, heldur staðirnir þar sem þjónustan þín stíflast. Þrjár dæmigerðar tegundir:

1) Sleep/Polling ersetzen: Wait mit Stop-Event

Ef þú keyrir tímabundna vinnu („athuga á 10 sekúndna fresti“), þá notaðu ekki Sleep(10000), heldur bíddu eftir atburði með timeout. Þá getur Stop-Event stöðvað biðina strax. Þetta dregur úr Stop-seinkun og kemur í veg fyrir tilfinninguna „Service reagiert nicht“.

2) Queue-Consumer: Work-Event + Stop-Event kombinieren

Ef þú ert með Producer/Consumer-arkitektúr (t.d. jobbað er sett í röð), þarftu merki sem vekur Consumer-ana. Algengt er að það sé annað TEvent (Work available). Consumer-inn bíður þá eftir tveimur handles: „Work“ eða „Stop“. Við Stop setur þú Stop-Event-ið og, ef þörf krefur, einnig Work-Event-ið, svo allir Consumer-ar komist örugglega úr biðinni.

3) Externe Calls (DB/HTTP): Timeouts und Abbruchpfade

Við gagnagrunnsviðköll eða HTTP-köll ræðst hvort þjónustan þín lokast hreint. Fyrir rekstur gildir: Kein Call ohne Timeout. Timeout er ekki lúxus heldur forsenda stjórnanleika. Enn fremur ættir þú á milli retry-/backoff-fasa alltaf að athuga Stop. Annars færðu hinn klassíska sjúkling: „Service stoppt nicht, weil er gerade 10 Retries mit Sleep macht“.

Í sumum bókasöfnum geturðu kallað fram afbrot beint (t.d. Query-Abbruch). Ef það er ekki mögulegt verður þú að stilla timeout-inn svo stuttan að hann ógildi ekki shutdown-timeoutið.

Stop Pending korrekt: Status, Logging und Erwartungsmanagement

Zeitmessung und Log-Analyse zur Diagnose von Stop-Timeouts bei Windows-Services
Fasa-logs og tímataka gera Stop-timeouts endurframkvæmanleg og útskýranleg.

Þegar þjónusta lokast er frá rekstrarsjónarmiði mikilvægt að skilja, hvar hún festist. Til þess þarftu tvo hluti:

  • Log-Marker í stop-pathanum: „Stop beiðinn“, „engin ný verkefni“, „bíða eftir Worker“, „Worker X hætti“, „lokun lokið“.
  • Messbare Zeiten: Hversu lengi tekur stöðvun? Hvaða fasi étur tíma? Hér dugar oft monotón tímamæling eins og GetTickCount64 eða TStopwatch (monoton = ekki skekkt af breytingum á kerfisstíma).

Ef þú skrifar í stöðvunarstíginn aðeins eina loggfærslu „Stopping…“, verður bilanaleit á vettvangi getgátaleikur. Í þjónustarekstri eru loggar oft eina upplýsingin sem þú færð án inngreps.

Hvaða Logs eru í þjónustum raunverulega gagnleg?

  • Service-PID, ræsingu­tími, Version/Build (án óþarfa viðbótarálags).
  • Fjöldi virkra workera, fjöldi verkefna í vinnslu.
  • Virkjar ytri háðir: „DB-Call läuft“, „HTTP-Request läuft“, „Datei-Flush läuft“ (aðeins samantekið, ekki hvert smáatriði).
  • Stop-Timeout náð: hvaða verkþræðir eru enn opnir?

Villuleit á vettvangi: gera endurtekningarhæft frekar en að giska

Stöðvunarvandamál birtast gjarnan aðeins í framleiðslu: annað álag, aðrar töf, önnur réttindi, önnur tímagluggi fyrir uppfærslur. Nokkur reynslubundin ráð:

Prófa þjónustuna undir stjórn

  • Stöðvun meðan á virku vinnslu stendur (ekki í hvíld).
  • Stöðvun meðan á ytri truflun stendur: DB tímabundið ótengjanleg, HTTP-endapunkt hægur, Fileshare óaðgengilegt.
  • Stöðvun samstundis eftir ræsingu (samkeppnisástand: verkþræðir enn í uppbyggingu).

Atburðaskoðari og Service Control Manager merki

Windows skráir þjónustuatburði, en þær færslur eru oft grófar. Betra er að þjónustan sjálf skrifi í loggskrá eða í Windows Event Log. Mikilvægt er að skráning virki enn í stöðvunarstígnum. Ef þú losar um loggerinn of snemma í lokun eða ef Flush festir/tefur, tapast nákvæmlega þær mikilvægu spor.

Gera hengjandi þræði sýnilega

Ef þú sérð endurtekið „Stop Timeout“, þá er þess virði að skoða stöðu þráða (t.d. með Debugger/Procdump í prófunarumhverfi). Oft finnur þú þá þráð í biðstöðu á handfangi sem aldrei er merkt, eða í netkalli án timeout. Lausnin er sjaldan „meiri Sleep“, heldur skilgreindur lokunarferill.

Hvenær er fyrirhöfnin virkilega þess virði?

Einfaldur þjónn sem hefur aðeins tímamæli og engar ytri háðir getur stundum einfaldlega stoppað. En ef eitt eða fleiri af eftirfarandi eiga við, er vel heppnaður vægur lokunarferill (graceful shutdown) nánast alltaf réttlætanlegur:

  • Þjónustan vinnur verkefni með aukaverkanir (skrif að skrám, DB-viðskipti, API-köll).
  • Það eru margir þræðir eða þræðapool.
  • Þjónustan er háð netauðlindum (DB, REST, Message Broker, Fileshares).
  • Reksturinn krefst áætlaðra viðhaldsglugga (endurræsingar, uppfærslur, failover).

Ávinningurinn er ekki „fegurð“, heldur rekstraröryggi: færri harðar lokanir ferla, færri ósamræmdir millistig, færri handvirk inngrip.

Hagnýtar gildrur: Hvað fer gjarnan úrskeiðis við lokun

1) Stop wird gesetzt, aber neue Jobs kommen trotzdem rein

Ef þú tekur við innkomandi vinnu (t.d. yfir Socket, skráar-trigger, Timer), þá þarftu í stöðvunarstígnum fyrst að stöðva móttöku nýrrar vinnu: loka Listener, afvirkja Timer, stöðva Scheduler. Annars ertu að elta endalok ferlisins þar sem ný verkefni halda að hefjast.

2) Cleanup blockiert (Flush, Close, Finalize)

„Að bara flusha allt“ getur verið hættulegt í þjónustufyrirkomulagi ef markmið (netdrif, fjarlæg logg, DB) er að hanga. Þess vegna: rýming já, en með takmörkuðum tíma. Ef þarf máttu ákveða hvaða gögn tapast úr minni í stað þess að loka alveg.

3) Lásar und Reihenfolge

Þegar Stop er kallað til notar þú oft sömu gagnastrúktúra og Worker-arnir (Queues, Caches, States). Ef stop-þráður heldur læsingum og bíður síðan eftir að Worker klárar, á meðan Workerarnir þurfa sömu læsingu, færðu Stop-Deadlock. Mótvörn: halda læsitímum stuttum, ekki „bíða undir læsingu“ í Stop-stígnum, skilgreina skýra röð.

4) Samhliða keyrsla við tvöfalt Stop

Í raunveruleikanum getur Stop verið triggarað oftar en einu sinni (t.d. Stop + Shutdown, eða Stop kemur aftur). Stop-stígurinn þinn ætti að vera idempotent: að setja Stop-Event er í lagi, en tvöföld Join/Free-rökfræði þarf að vera vel varin (t.d. með atómsku flaggi).

Vinnslusjón: Hvað kerfisstjórar og IT-leiðtogar búast við af þjónustunni

Fyrir rekstur og stjórnun skiptir ekki máli hversu „fallegur“ kóðinn er, heldur hvort þjónustan:

  • við Stop ljúki áreiðanlega (fyrirsjáanleg, án hangandi ferla),
  • við Stop framleiði ekki ósamræmd gögn (t.d. hálfar skrár, opnar færslur),
  • í villutilvikum skili gagnlegum loggum,
  • við viðhaldsglugga og deployments sé fyrirsjáanleg.

Þetta er líka ástæðan fyrir því að Stop-Timeout er ekki bara „forritaraefni“: það hefur áhrif á plástrahringa, endurheimtartíma og hvort sjálfvirk deployments séu yfirleitt möguleg.

Konkrét leiðarljós fyrir trausta Shutdown-hönnun

Ef þú vilt staðla þetta hagnýtt hafa þessi leiðarljós reynst vel:

  • Eitt globalt Stop-Event, Manual Reset, búið til snemma í þjónustulífsferlinu, sleppt seint.
  • Enginn Sleep í Worker-loops án Stop-virks valkosts (Wait með Timeout).
  • Allir ytri kallar með Timeouts (DB, HTTP, Fileshares). Veldu Timeouts þannig að þeir passi í Shutdown-Timeout þinn.
  • Stop-Timeout sem stilling (t.d. í INI/Registry), svo rekstur geti brugðist án þess að þurfa að endurforrita.
  • Þrepalíkan: Fyrst graceful (láta núverandi jobba klárast), síðan valkvætt „soft abort“ (engin ný skref), og að lokum harður exit sem síðasta úrræði.
  • Góð Stop-logs með stigum og tímatöku.

Niðurstaða: TEvent + Stop-Timeout er ekki lúxus, heldur stýring

Stöðnuð Stop-aðgerð er sjaldan einangruð villa – yfirleitt er um arkitektúrbilun að ræða: vinna keyrir í þráðum eða í læsandi köllum sem þekkja ekki sameiginlegt Stop-signal. Með skýru Stop-Event (TEvent, Manual Reset), stop-virkum Waits í stað Sleep, samkvæmum Timeouts fyrir ytri háða og skilgreindu Shutdown-Timeout færðu þjónustu sem er í rekstri fyrirsjáanleg.

Kóðinn borgar sig sérstaklega ef þjónustan þín keyrir í framleiðsluumhverfi með viðhaldsgluggum, sjálfvirkum deployments eða krítískum aukaverkunum. Þá er „Graceful Shutdown“ ekki fegurðarmál heldur hluti af traustum rekstri og færri eskaleringum við næstu endurræsingu.

Ef þú vilt setja Stop-stíg ykkar upp rétt eða yfirfara tiltekinn Delphi-service fyrir trausta shutdown-rökfræði og rekstraröryggi, er tæknilegur sparrings-call oft hraðasti vegurinn að skýrum aðgerðum: Hafðu samband.

Fyrir þetta efni skipta einnig máli Delphi Windows Service og Tevent Delphi. Greinin setur þessa þætti í skiljanlegt samhengi og sýnir hvað skiptir máli í daglegu starfi.

Ræddu verkefni eða endurnýjunaráform með Net-Base.

Næsta skref

Ef efnið verður að raunverulegu verkefni, ætti snemma að skoða kerfisarkitektúr, núverandi kerfi og rekstur í sameiningu.

Við styðjum ekki aðeins við einstakar spurningar, heldur einnig þegar úr kóðabútum, eldri kerfum eða gáttahugmyndum þarf að verða traust fyrirtækjaverkefni.

  • Núverandi staða, markmynd og tæknileg áhætta eru metin saman.
  • REST, aðgangur að gögnum, gáttir og innleiðing verða ekki flutt til síðari tíma sem afleiðingar.
  • Þú sérð snemma hvaða leið er efnahagslega og rekstrarlega framkvæmanleg.

Deila færslu

Deila þessari færslu beint

LinkedIn, X, XING, Facebook, WhatsApp og tölvupóstur eru strax í boði. Fyrir Instagram undirbúum við tengil og stuttan texta strax.

Tölvupóstur

Instagram opnast í nýjum flipa. Tengill og stuttur texti eru afritaðir í klippiborðið á undan.