From f535771b21375b9908b93a291892b0440898808b Mon Sep 17 00:00:00 2001 From: Filipe Toscano Date: Fri, 24 Jan 2025 20:22:32 +0400 Subject: [PATCH] Add payload consideration when using Hangfire --- examples/AsyncHangfire/Jobs/EmailSendJob.cs | 29 +++++++++++++++++++++ examples/AsyncHangfire/README.md | 23 ++++++++++++---- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/examples/AsyncHangfire/Jobs/EmailSendJob.cs b/examples/AsyncHangfire/Jobs/EmailSendJob.cs index fe593e4..82c3724 100644 --- a/examples/AsyncHangfire/Jobs/EmailSendJob.cs +++ b/examples/AsyncHangfire/Jobs/EmailSendJob.cs @@ -25,6 +25,24 @@ public async Task BackgroundSendAsync( EmailMessage message, CancellationToken c _logger.LogDebug( "Email to {To}: {Subject}", message.To, message.Subject ); + /* + * + */ + if ( message.Attachments?.Count > 0 ) + { + foreach ( var att in message.Attachments ) + { + if ( att.Path?.StartsWith( "load:" ) == false ) + continue; + + _logger.LogDebug( "Attachment: Load {Filename} based on {LoadPath}", att.Filename, att.Path ); + + att.Content = await ContentLoadAsync( att.Path!, cancellationToken ); + att.Path = null; + } + } + + /* * Send email */ @@ -32,4 +50,15 @@ public async Task BackgroundSendAsync( EmailMessage message, CancellationToken c _logger.LogInformation( "Sent with Id {EmailId}", resp.Content ); } + + + /// + private async Task ContentLoadAsync( string attachmentPath, CancellationToken cancellationToken ) + { + await Task.Delay( 1_000, cancellationToken ); + + // TODO: Load based on attachmentPath + + throw new NotImplementedException(); + } } \ No newline at end of file diff --git a/examples/AsyncHangfire/README.md b/examples/AsyncHangfire/README.md index fc68089..36c9172 100644 --- a/examples/AsyncHangfire/README.md +++ b/examples/AsyncHangfire/README.md @@ -40,14 +40,27 @@ Explained |------|------------------------------------------------------------- | 1 | When hitting `/test`, the `Get` method of `Controllers/TestController.cs` runs. | 2 | `BackgroundJob.Enqueue` will create an instance of the email send job. -| 3 | When viewing `/jobs`, one job will be enqueued for execution. -| 4 | Refresh `/jobs`, and the job will change to scheduled. -| 5 | Refresh `/jobs`, and the job will change to processing. - +| 3 | Hangfire server will pick up from queue and invoke `EmailSendJob.BackgroundSendAsync` method. +| 4 | If an exception is thrown, Hangfire server will retry the job. +| 5 | Otherwise, job will be marked as Succeeded. Considerations --------------------------------------------------------------------- As per the [best practices](https://docs.hangfire.io/en/latest/best-practices.html) documentation, -it is advised to keep the +it is advised to keep the payload size small. + +> Method invocation (i.e. a job) is serialized during the background job +> creation process. Arguments are converted into JSON strings using the +> TypeConverter class. If you have complex entities and/or large objects; +> including arrays, it is better to place them into a database, and then pass +> only their identities to the background job. + +As such, it is desireable to avoid inline attachments, since the +entire `byte[]` would be stored in the Hangfire job database. + +One alternative of setting the value of `Content` property, would be to +re-use the `Path` property with special value such that the `EmailSendJob` +can then load the content prior to sending email. See `Jobs/EmailSendJob.cs` +for a skeleton of such code.