3

We have a windows service created with Topshelf (4.0.1). Is there any way how to delay it's stopping during operating system shutdown?

I know it's pretty problematic desire so an explanation: Let's say that we have win service what needs some additional time during shutdown (some tasks have to be completed correctly and now we have no way how to perform it faster).

It's possible to delay standard service stop (performed e.g. by Powershell Stop-Service cmdlet or so...) by calling RequestAdditionalTime() in the service OnStop(). It all works well when stopping the service in such "standard" way... But RequestAdditionalTime() cannot be used during system shutdown (i.e. windows service OnShutdown()). Because of that I've implemented this SO answer approvach in classical windows service and 3:20 delay was achieved by that (that's what we need).

But mentioned SO answer solution (hack, better to say) doesn't work with Topshelf.

Is there any way how to do it with Topshelf?

Community
  • 1
  • 1
zbynour
  • 19,747
  • 3
  • 30
  • 44
  • 1
    When a power cut hits, you don't get any time to complete things correctly. Think of system shutdown as a power cut that you get a little warning for. If you need to do more work, arrange for it to happen well *before* the power cut hits. It may be painful but re-architecting your system to not need to do so much work during system shutdown is the better long term approach. – Damien_The_Unbeliever Feb 23 '17 at 08:51
  • E.g. SQL Server has a transaction log where everything it *will do* when a transaction is completed is recorded. During the next *startup*, it uses that log to determine which transaction had been completed and to ensure their effects take place, and similarly to roll back any transactions that didn't complete. In this way, it's able to shut down fast at the expense of more work during startup - but it has to be this way to be *resilient* to sudden shutdowns (including, as mentioned, power cuts) – Damien_The_Unbeliever Feb 23 '17 at 08:54
  • 1
    In ideal world where everything could be done in transaction, it is really not problem. Imagine you sending e-mail, you want to minimize cases there you send duplicate just because you would not be able to write information that you already finished sending. – Bobris Feb 23 '17 at 10:00

1 Answers1

2

It should be possible to register a custom EnvironmentBuilder (using extension method UseEnvironmentBuilder on a HostConfigurator instance) that returns a customized implementation of the HostEnvironment interface. Custom implementation of the HostEnvironment.CreateServiceHost method can return any implementation of Host you need (e.g. a Host that Run()s your ServiceBase).

You can reuse implementation of other HostEnvironment / Host methods by forwarding calls to WindowsHostEnvironment and WindowsServiceHost classes, respectively. WindowsHostEnvironment instance can be simply created in your custom EnvironmentBuilder constructor (and passed into custom HostEnvironment).

zbynour
  • 19,747
  • 3
  • 30
  • 44
tomasdeml
  • 339
  • 2
  • 7
  • @zbynour I'm trying to create similar thing in Topshelf. Could You please share Your code? – Misiu May 18 '17 at 10:42
  • @Misiu It should be enough to follow the answer itself. What particular issue are you interested about? – zbynour May 18 '17 at 12:57
  • @zbynour I don't know how to use `UseEnvironmentBuilder` and `ServicePreshutdownBase` from Your question. If I use `UseEnvironmentBuilder` I must pass `EnvironmentBuilderFactory` and right here I don't know how to combine those two – Misiu May 18 '17 at 13:08
  • @Misiu Take a look at that one: https://gist.github.com/zbynourcz/575110dfd65becd3078da6da8353df85 `FooHostEnvironment.CreateServiceHost()` meth is crucial since you return `Host` instance there. As a `Host` instance you can use your own implementation inheriting `Topshelf.Runtime.Windows.WindowsServiceHost` (what implements `ServiceBase`). Does it help? – zbynour May 19 '17 at 15:44