Hi @tomboo. Yes, you can use Hangfire API to get the details. Dashboard page uses the following code to determine the numbers. Total number is the sum of all the given numbers. Total number of non-finished jobs is created
+ pending
+ processing
, and so on.
using (var connection = Storage.GetConnection())
{
var storageConnection = connection as JobStorageConnection;
created = storageConnection.GetSetCount($"batch:{BatchId}:created") + storageConnection.GetSetCount($"batch:{BatchId}:created:batches");
pending = storageConnection.GetSetCount($"batch:{BatchId}:pending") + storageConnection.GetSetCount($"batch:{BatchId}:pending:batches");
processing = storageConnection.GetSetCount($"batch:{BatchId}:processing") + storageConnection.GetSetCount($"batch:{BatchId}:processing:batches");
succeeded = storageConnection.GetSetCount($"batch:{BatchId}:succeeded") + storageConnection.GetSetCount($"batch:{BatchId}:succeeded:batches");
finished = storageConnection.GetSetCount($"batch:{BatchId}:finished") + storageConnection.GetSetCount($"batch:{BatchId}:finished:batches");
}
However, if you want to show those numbers to your users (not to your administrators), it is always better to add dedicated entities to your domain logic that will provide such details without querying Hangfire itself. This will protect your code from changes in Hangfire itself (these are breaking ones, and will only be in major releases), and will allow you to use queries whatever you want.
For example, if you send mass newsletter and using SQL Server for your application’s primary data, and use batches for campaigns, it’s better to create table Campaign
with Id
, Template
, and CreatedAt
and table Letter
with columns Id
, CampaignId
, Name
, Email
and Status
(sent/unsent).
Before creating jobs you create records in that tables, and tell Hangfire to use Letter
's Id
when enqueueing the SendLetter(int letterId)
method that will look like this in pseudo-code:
public void SendLetter(int letterId)
{
// RepeatableRead is to lock the row and hold it, it is possible that
// under rare circumstances another worker will pick up a job with
// the same letterId.
using (var transaction = BeginTransaction(IsolationLevel.RepeatableRead))
{
var letter = GetLetterById(letterId);
if (letter == null) return;
var campaign = GetCampaignById(letter.CampaignId);
if (campaign == null) throw new CampaignAbsentException();
SmtpSend(letter.Name, letter.Email, campaign.Template);
ChangeLetterStatus(letterId, letterStatus.Sent);
transaction.Commit();
}
}
And create campaigns and letters before creating your jobs:
var transaction = BeginTransaction();
var campaign = CreateCampaign();
var letter = CreateLetter();
var batch = CreateBatch(campaignId);
var job = CreateJob(letterId);
transaction.Commit();
And now you can create use regular T-Sql to query how many letters are still unsent, what are the top campaigns by the number of letters, etc. And this is possible, because now your domain logic now knows that some of your entities may be processed or non-processed yet.