private async IAsyncEnumerable <SentChecklist> YieldChecklistWatchdogEntryAsync( IList <IList <object> > rows, [EnumeratorCancellation] CancellationToken cancellationToken) { var entries = new ChecklistWatchdogEntry[rows.Count - 1]; for (var i = 0; i < entries.Length; i++) { var row = rows[i + 1]; if (row.Count < 12) { continue; } if (string.IsNullOrWhiteSpace(row[0].ToString())) { continue; } var entry = new ChecklistWatchdogEntry { ChecklistName = row[1].ToString(), ChecklistMessage = row[2].ToString(), Type = ChecklistWatchdogEntryType.Daily, NotifyFoundMessage = row[8].ToString(), NotifyNotFoundMessage = row[10].ToString() }; TimeSpan.TryParseExact(row[3].ToString(), @"hh\:mm", null, out entry.SendAt); { var sendAtDaysOfWeek = row[4].ToString(); if (!string.IsNullOrEmpty(sendAtDaysOfWeek)) { var separatedDaysOfWeek = sendAtDaysOfWeek.Split(','); entry.PublishDaysOfWeek = new int[separatedDaysOfWeek.Length]; for (var j = 0; j < separatedDaysOfWeek.Length; j++) { int.TryParse(separatedDaysOfWeek[j].AsSpan(), out entry.PublishDaysOfWeek[j]); } entry.Type = ChecklistWatchdogEntryType.Weekly; } } if (entry.Type != ChecklistWatchdogEntryType.Weekly) { var sendAtDays = row[5].ToString(); if (!string.IsNullOrEmpty(sendAtDays)) { var separatedDays = sendAtDays.Split(','); entry.PublishDays = new Range[separatedDays.Length]; for (var j = 0; j < separatedDays.Length; j++) { var day = separatedDays[j]; if (day.Contains('-', StringComparison.Ordinal)) { var dayRange = day.Split('-', 2); int.TryParse(dayRange[0], out var start); int.TryParse(dayRange[1], out var end); entry.PublishDays[j] = start..end; } else { int.TryParse(day, out var index); entry.PublishDays[j] = index..index; } } entry.Type = ChecklistWatchdogEntryType.Monthly; } } long.TryParse(row[6].ToString().AsSpan(), out entry.PublishChatId); long.TryParse(row[7].ToString().AsSpan(), out entry.NotifyFoundChatId); long.TryParse(row[9].ToString().AsSpan(), out entry.NotifyNotFoundChatId); long.TryParse(row[11].ToString().AsSpan(), out entry.RestaurantChatId); entries[i] = entry; } entries = entries.Where(entry => entry != null).ToArray(); using var sentChecklists = new BlockingCollection <SentChecklist>(); var tasks = new Task[entries.Length]; for (var i = 0; i < entries.Length; i++) { tasks[i] = RunChecklistWatchdogForEntryAsync(entries[i], sentChecklists, cancellationToken); } var resultTask = Task.Factory.ContinueWhenAll(tasks, _ => sentChecklists.CompleteAdding(), cancellationToken); while (sentChecklists.TryTake(out var sentChecklist, -1, cancellationToken)) { yield return(sentChecklist); } if (!resultTask.IsCompleted) { await resultTask.ConfigureAwait(false); } else if (resultTask.IsFaulted) { // ReSharper disable once PossibleNullReferenceException throw resultTask.Exception; } }
private async Task RunChecklistWatchdogForEntryAsync(ChecklistWatchdogEntry entry, BlockingCollection <SentChecklist> sentChecklists, CancellationToken cancellationToken) { var restaurant = _data.Restaurants.Find(r => r.ChatId == entry.RestaurantChatId); if (restaurant == null) { return; } var sendAtDaysOfWeek = entry.PublishDaysOfWeek?.Where(dow => dow > 0 && dow < 8) .Select(dow => dow == 7 ? DayOfWeek.Sunday : (DayOfWeek)dow); TimeSpan GetDelay(out DayOfWeek todayIsDayOfWeek, out int todayIsDayOfMonth) { var now = _cultureService.NowFor(restaurant); todayIsDayOfWeek = now.DayOfWeek; todayIsDayOfMonth = now.Day; return(now.TimeOfDay < entry.SendAt ? entry.SendAt - now.TimeOfDay : entry.SendAt + TimeSpan.FromDays(1d) - now.TimeOfDay); } while (!cancellationToken.IsCancellationRequested) { await Task.Delay(GetDelay(out var todayIsDayOfWeek, out var todayIsDayOfMonth), cancellationToken).ConfigureAwait(false); // ReSharper disable once SwitchStatementMissingSomeCases switch (entry.Type) { case ChecklistWatchdogEntryType.Weekly: { if (!sendAtDaysOfWeek.Contains(todayIsDayOfWeek)) { continue; } break; } case ChecklistWatchdogEntryType.Monthly: { if (entry.PublishDays.Any(expectedRangeOfDays => expectedRangeOfDays.Start.Value < todayIsDayOfMonth || expectedRangeOfDays.End.Value > todayIsDayOfMonth)) { continue; } break; } } try { var totalAttachmentsFound = 0; await foreach (var messageId in _mailClient.ExecuteForRestaurantAsync(entry.PublishChatId, entry.ChecklistName, entry.ChecklistMessage, cancellationToken)) { var sentChecklist = new SentChecklist { Date = _cultureService.NowFor(restaurant).Date, MessageId = messageId, ChecklistName = entry.ChecklistName }; sentChecklists.TryAdd(sentChecklist, -1, cancellationToken); totalAttachmentsFound++; } if (totalAttachmentsFound == 0) { if (entry.NotifyNotFoundChatId != 0L && !string.IsNullOrWhiteSpace(entry.NotifyNotFoundMessage)) { try { await _client.SendTextMessageAsync(entry.NotifyNotFoundChatId, entry.NotifyNotFoundMessage, disableWebPagePreview : true, cancellationToken : cancellationToken) .ConfigureAwait(false); } catch (Exception e) { Console.WriteLine(e); } } } else { if (entry.NotifyFoundChatId != 0L && !string.IsNullOrWhiteSpace(entry.NotifyFoundMessage)) { try { await _client.SendTextMessageAsync(entry.NotifyFoundChatId, entry.NotifyFoundMessage, disableWebPagePreview : true, cancellationToken : cancellationToken) .ConfigureAwait(false); } catch (Exception e) { Console.WriteLine(e); } } } } catch (Exception e) { Console.WriteLine(e); } } }