Безопасно ли запускать задачу из метода ContinueWith той же задачи? - PullRequest
0 голосов
/ 13 июня 2018

У меня есть служба Windows с прослушивателем, который выполняет цикл внутри задачи, которая прослушивает ServiceBus.Если соединение обрывается или возникает какая-то другая проблема, я хочу снова запустить задачу прослушивателя.Поскольку я не ожидаю выполнения задачи, так как она должна выполняться вечно, мне нужно использовать ContinueWith и проверить, не произошло ли исключение.Если это так, я хочу начать точно такой же процесс.

Таким образом, вопрос заключается в следующем: безопасно ли делать это таким образом в отношении контекста выполнения, памяти, трассировки стека или некоторых других вещей, о которых я не думал?

Кажется, что код работаетвсе в порядке и переподключается, если сеть была отключена и вернулась в рабочее состояние, трассировка стека для исключений также кажется правильной, но я боюсь некоторых ловушек, о которых я не думал.

private void StartReceiving(string connectionString)
{
    _receiverHost
        .StartReceiving(connectionString)
        .ContinueWith(c =>
        {
            if (c.IsFaulted)
            {
                Thread.Sleep(60000);
                StartReceiving(connectionString);
            }
        }
    });

}

Ответы [ 2 ]

0 голосов
/ 13 июня 2018

Я попробовал ваш код в каком-то дополнительном коде следующим образом, и я не смог увидеть никаких проблем с контекстом выполнения, памятью, трассировкой стека.

public class Receiver
{
    public async Task StartReceiving(string connectionString)
    {
        var task = Task.Run(() =>
        {
            try
            {
                throw new Exception("connection lost");
            }
            catch (Exception)
            {
                /* log the exception, or something */
                throw;
            }
        });
        await task;
    }
}

public class Server
{
    ILog log = LogManager.GetLogger<Server>();

    public bool IsStopped { get; private set; } = false;
    private Receiver _receiverHost = new Receiver();
    public void StartReceiving(string connectionString)
    {
        _receiverHost
            .StartReceiving(connectionString)
            .ContinueWith(async c =>
            {
                if (c.IsFaulted)
                {
                    var n = Process.GetCurrentProcess().Threads.Count;
                    var timestamp = DateTime.UtcNow;
                    await Task.Delay(1000);
                    log.Debug($"Task Delay: {(DateTime.UtcNow - timestamp).TotalSeconds} seconds");
                    StartReceiving(connectionString);
                }
            });
    }
}

[TestFixture]
public class TestServerRetry
{
    [TestCase]
    public async Task TestRetry()
    {
        var server = new Server();
        server.StartReceiving("test connection");
        while (!server.IsStopped)
            await Task.Delay(100);
    }
}
0 голосов
/ 13 июня 2018

Чтобы ответить на ваш вопрос:

"Безопасно ли делать это таким образом в отношении контекста выполнения, памяти, трассировки стека или некоторых других вещей, о которых я не задумывался?"

Да;нет никаких проблем в отношении любой из упомянутых областей, о которых я могу думать.Вы в основном выходите из предыдущего задания и вводите новое задание.Ваша память очищается, когда вы продолжаете выполнение следующей задачи, и трассировка стека начинается с задачи, создающей выполнение.

Однако я бы лучше прокомментировал проблемы, возникающие в связи с обработкой ошибок и прерыванием выполнения, чтоэта реализация не поможет вам найти ошибку, подключиться к альтернативному адресу или какой-либо другой логике, которую вы можете ввести.По моему мнению, вы вводите неожиданную сложность в эту реализацию.

Если бы мне пришлось реализовать этот класс, я бы скорее вызвал отключенное событие, которое должен решить класс, использующий этот объект.Это даст вам гораздо более широкий спектр возможностей, например, уведомление других зависимых классов.

Кроме того, замораживание нити обычно не является хорошим решением.Я бы предпочел запустить таймер или что-то подобное.

...