Hangfire Discussion

Big class file vs Small class file. Which is better for hangfire?


#1

Let’s say I have a class with 200 functions and procedures. Only 3 of them used by BackgroundJob.Enqueue function. Rest is some bunch of functions for other purposes. I can separate these 3 into new class.

What I want to know is should I do that ? Or can I continue to use my big class (but actually only 3 of them) without any concern ? Is there any performance issues, storage size issues ?

best.


#2

Hangfire only need to serialize the typename, method name and your arguments.

It doesn’t matter how many methods/members the type contains, Hangfire never serializes any of that. Main concern is to make your type and number of arguments to the method as small as possible since that is what is going to be serialized.

Ie. if you have a lot of input-data to your method, its better to store that as a record somewhere in a database and only pass a id to your method which then knows how to load up your argument data.


#3

@burningice is correct that none of it matters from a hangfire perspective, but to answer your question of what should you do. From an architectural perspective if the only purpose these 3 functions serve is to execute specific fire and forget functionality, I would want them separated out and have the class named and namespaced appropriately to signal exactly what it does. Again though this is more of an architectural question than a performance question.


#4

Giving specific architectural advise with so little context is always hard, but i can say for my own point of view is that i always encapsulate each task i want Hangfire to handle into a class which has a single Execute-method taking some simple arguments. The class is registered in a IoC container so Hangfire can instantiate it and inject necessary dependencies and i then register the task in Hangfire like this

BackgroundJob.Enqueue<PerformNewNotificationTask>(t => t.Execute(source, sourceId, title, url, websiteId, ci, null));

So you see here that i don’t instantiate the class beforehand, Hangfire will do that when necessary, and the task-class can take dependcies in its contructor.

 public class PerformNewNotificationTask
    {
        private const string Template = "Notifications.NewNotification";

        private readonly MailService _mailService;
        private readonly SentMailsService _sentMailsService;

        public PerformNewNotificationTask(MailService mailService, SentMailsService sentMailsService)
        {
            _mailService = mailService;
            _sentMailsService = sentMailsService;
        }

        public void Execute(string source, Guid sourceId, string title, string url, Guid websiteId, CultureInfo ci, IJobCancellationToken cancellationToken)
        {
            Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = ci;

            using (var data = new DataConnection(ci))
            {
                var subscribers = data.Get<INotificationsSubscriber>().Where(n => n.Culture == ci.Name && n.WebsiteId == websiteId).ToList();
                foreach (var subscriber in subscribers)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    var subjects = (subscriber.Subjects ?? String.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                    if (subjects.Any() && !subjects.Contains(source))
                    {
                        continue;
                    }

                    var id = $"{subscriber.Id}:{sourceId}";
                    if (_sentMailsService.AlreadySent<NotificationsService>(Template, id))
                    {
                        continue;
                    }

                    var mailModel = new NewNotificationModel
                    {
                        To = subscriber.Email,
                        Title = title,
                        Url = url,
                        EditUrl = $"~/page({NotificationsService.PageId})?cmd=edit&email={subscriber.Email}&token={subscriber.Id}",
                        UnsubscribeUrl = $"~/page({NotificationsService.PageId})?cmd=unsubscribe&email={subscriber.Email}&token={subscriber.Id}"
                    };

                    _mailService.BuildMessageAndEnqueue(mailModel);

                    _sentMailsService.CreateLogEntry<NotificationsService>(Template, id);
                }
            }
        }
    }