HangfireIO / HangfireIO/Hangfire
Hangfire workers pick up same job one after another
- Dominant language
- C#
- Stars
- 10.1k
- Forks
- 1.8k
- Avg merge
- 1h 19m
- Merged PRs (30d)
- 1
Description
MRE:
DB -> sqlite, `hangfire.db`
Registering in program.cs of an api project -> `builder.Services.AddPersonalHangfire(hangfireConnectionString);`
Service extension ->
```
public static IServiceCollection AddPersonalHangfire(this IServiceCollection services, string dbConnectionString)
{
var sqliteOptions = new SQLiteStorageOptions();
services.AddHangfire(configuration => configuration
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSQLiteStorage(dbConnectionString, sqliteOptions)
);
services.AddHangfireServer();
return services;
}
```
Hangfire job invoke -> `BackgroundJob.Enqueue(job => job.SendEmail(message));`
Enqueued job implementation ->
```
public class EmailJob
{
private readonly IEmailManager _emailManager;
public EmailJob(IEmailManager emailManager)
{
_emailManager = emailManager;
}
public Task SendEmail(Message message)
{
return _emailManager.SendEmailAsync(message);
}
}
```
Actual mail method ->
```
public async Task SendEmailAsync(Message message)
{
if (_emailOptions?.CurrentValue is null)
{
Log.Error("Cannot retrieve mailbox configuration.");
return false;
}
var isMessageSent = false;
using var client = new SmtpClient();
try
{
var messageMime = CreateMessage(message);
await client.ConnectAsync(_emailOptions.CurrentValue.Host, int.Parse(_emailOptions.CurrentValue.Port), SecureSocketOptions.SslOnConnect);
await client.AuthenticateAsync(_emailOptions.CurrentValue.Email, _emailOptions.CurrentValue.Password);
await client.SendAsync(messageMime);
isMessageSent = true;
}
catch (Exception ex)
{
Log.Error($"Email to recipent {message.To} could not be sent.", ex.Message);
isMessageSent = false;
}
finally
{
if (client.IsConnected)
{
await client.DisconnectAsync(true);
client.Dispose();
}
}
return isMessageSent;
}
```
What happens?
User gets sent 20 emails, after one method invocation. Shouldn't it work like queue? When one worker takes the job, rest can not see it? What should i do to make only one worker send the email?
Temporary solution (not satisfied):
Set worker count to 0 ->
```
services.AddHangfireServer(options =>
{
options.WorkerCount = 1;
});
```
Contributor guide
Research direction
Start in Program.cs with AddPersonalHangfire and AddHangfireServer, then trace BackgroundJob.Enqueue to EmailJob.SendEmail. Inspect the worker configuration and job execution history to determine why one invocation results in 20 sends, including whether the job is enqueued or retried repeatedly. Done means the cause of the duplicate sends is identified and the expected single-send behavior is verified.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp, sqlite
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100