How to handle async Start() errors in TopShelf

后端 未结 1 1449
执念已碎
执念已碎 2021-02-06 03:35

I have a TopShelf service that uses async code to connect to web services and other application servers.

If it\'s unable to initialize its connections on startup, the se

1条回答
  •  予麋鹿
    予麋鹿 (楼主)
    2021-02-06 03:49

    Firstly, async void is almost always incorrect, except in some truly fire-and-forget scenarios. You want to change that to async Task.

    Then sometimes you just have to use .Wait() at the border between sync and async code. In this case you probably want to rename your current async Start() method to StartAsync() and add a Start() method that calls it:

    public void Start()
    {
        StartAsync().Wait();
    }
    
    public async Task StartAsync()
    {
        await Init();
        while (!_canceller.Token.IsCancellationRequested)
        {
            await Poll();
        }
    }
    

    However, you have another issue, in that TopShelf's Start() method is not a "Run"() method; i.e. you are supposed to return from that method as soon as your service is started, not remain there while the service runs. Given you're already using async-await, I'd probably instead not call Wait() in Start(), but save the Task returned from StartAsync(), then when Stop() is called, signal your Task to stop using that existing _canceller, and only then in Stop() call .Wait(), leaving you with something like this:

    private Task _serviceTask;
    
    public void Start()
    {
        Init().Wait();
        _serviceTask = ExecuteAsync();
    }
    
    public void Stop()
    {
        _canceller.Cancel();
        _serviceTask.Wait();
    }
    
    public async Task ExecuteAsync()
    {
        while (!_canceller.Token.IsCancellationRequested)
        {
            await Poll();
        }
    }
    

    I should add that the way you had it, you probably kind-of get away things to an extent, in the sense that your async Start() method will return to TopShelf as soon as it hits the first await, but will continue executing. If your Stop() method calls _canceller.Cancel() then your async Start() method will terminate next time Poll() is called.

    However the above is cleaner, and you have to ability to wait until the last Poll() finishes executing, which you didn't before. You will also be able to handle exceptions, as you mention.

    Edit I'd also move the Init() call into Start(), as above.

    0 讨论(0)
提交回复
热议问题