• Jobs
  • About Us
  • professionals
    • Home
    • Jobs
    • Courses and challenges
  • business
    • Home
    • Post vacancy
    • Our process
    • Pricing
    • Assessments
    • Payroll
    • Blog
    • Sales
    • Salary Calculator

0

100
Views
¿Debería DisposeAsync lanzar excepciones de tareas en segundo plano o dejar que el cliente las observe explícitamente?

No creo que esta pregunta sea un duplicado de "Forma correcta de tratar las excepciones en DisposeAsync" .

Digamos que mi clase implementa IAsynsDisposable porque tiene una tarea en segundo plano de ejecución prolongada y DisposeAsync finaliza esa tarea. Un patrón familiar podría ser la propiedad Completion , por ejemplo, ChannelReader<T>.Completion (a pesar de que ChannelReader no implementa IAsynsDisposable ).

¿Se considera una buena práctica propagar las excepciones de la tarea de Completion fuera de DisposeAsync ?

Aquí hay un ejemplo completo que se puede copiar/pegar en un dotnet new console . Tenga en cuenta await this.Completion . Finalización dentro DisposeAsync :

 try { await using var service = new BackgroundService(TimeSpan.FromSeconds(2)); await Task.Delay(TimeSpan.FromSeconds(3)); } catch (Exception ex) { Console.WriteLine(ex); Console.ReadLine(); } class BackgroundService: IAsyncDisposable { public Task Completion { get; } private CancellationTokenSource _diposalCts = new(); public BackgroundService(TimeSpan timeSpan) { this.Completion = Run(timeSpan); } public async ValueTask DisposeAsync() { _diposalCts.Cancel(); try { await this.Completion; } finally { _diposalCts.Dispose(); } } private async Task Run(TimeSpan timeSpan) { try { await Task.Delay(timeSpan, _diposalCts.Token); throw new InvalidOperationException("Boo!"); } catch (OperationCanceledException) { } } }

Alternativamente, puedo observar service.Completion explícitamente en el código del cliente (e ignorar sus excepciones dentro de DiposeAsync para evitar que se arrojen dos veces), como a continuación:

 try { await using var service = new BackgroundService(TimeSpan.FromSeconds(2)); await Task.Delay(TimeSpan.FromSeconds(3)); await service.Completion; } catch (Exception ex) { Console.WriteLine(ex); Console.ReadLine(); } class BackgroundService: IAsyncDisposable { public Task Completion { get; } private CancellationTokenSource _diposalCts = new(); public BackgroundService(TimeSpan timeSpan) { this.Completion = Run(timeSpan); } public async ValueTask DisposeAsync() { _diposalCts.Cancel(); try { await this.Completion; } catch { // the client should observe this.Completion } finally { _diposalCts.Dispose(); } } private async Task Run(TimeSpan timeSpan) { try { await Task.Delay(timeSpan, _diposalCts.Token); throw new InvalidOperationException("Boo!"); } catch (OperationCanceledException) { } } }

¿Hay consenso sobre qué opción es mejor?

over 3 years ago · Santiago Trujillo
1 answers
Answer question

0

Por ahora, me he decidido por una clase de ayuda reutilizable LongRunningAsyncDisposable ( aquí hay una esencia , advertencia: apenas probada todavía), que permite:

  • para iniciar una tarea en segundo plano;
  • detenga esta tarea (a través de un token de cancelación) llamando a IAsyncDisposable.DisposeAsync en cualquier momento, de una manera segura para subprocesos y amigable con la concurrencia ;
  • configure si DisposeAsync debe volver a lanzar las excepciones de la tarea ( DisposeAsync esperará la finalización de la tarea de cualquier manera, antes de realizar una limpieza);
  • observe el estado, el resultado y las excepciones de la tarea en cualquier momento a través de la propiedad LongRunningAsyncDisposable.Completion .
over 3 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Our process Sales
Legal
Terms and conditions Privacy policy
© 2025 PeakU Inc. All Rights Reserved.

Andres GPT

Recommend me some offers
I have an error