public async Task Execute(IJobExecutionContext context) { using (var scope = ResourceLocator.ObtainLifetimeScope()) { var crawlers = scope.Resolve <IEnumerable <IDomainCrawler> >(); var searchCrawlers = scope.Resolve <IEnumerable <IDomainSearchCrawler> >(); var monitor = scope.Resolve <IDomainMonitor>(); using (var huntService = scope.Resolve <IHuntService>()) { huntService.ConfigureIncludes().WithChain(query => query.Include(hunt => hunt.HuntedItem.Domain)).Commit(); //first we are getting all hunts that are meant to be fired in this interval var hunts = await huntService.GetAllWithIds((long[])context.JobDetail.JobDataMap[HuntUpdateJobMapIdsPropertyKey]); //now we will group them by items they are bound to in case of them repeating foreach (var huntedItems in hunts.GroupBy(hunt => hunt.HuntedItem.Id)) { //each domain will be checked in pararell var updateTasks = new List <Task>(); foreach (var huntedItemsWithinDomain in huntedItems.GroupBy(hunt => hunt.HuntedItem.Domain, HuntDomain.IdComparer)) { foreach (var hunt in huntedItemsWithinDomain) { updateTasks.Add(new Task(async() => { using (await monitor.WaitForDomainAccess(huntedItemsWithinDomain.Key)) { await ProcessItemUpdate(crawlers, searchCrawlers, hunt); } })); } } await Task.WhenAll(updateTasks); } } } }