public static async Task <int> PublishTweets([ActivityTrigger] List <TweetProcessingData> tpds, ILogger log) { log.LogInformation($"A_PublishTweets: Publishing {tpds.Count} tweets."); double minScoreBLAlert = TweetAnalysis.GetScoreFromEnv("AZTWITTERSAR_MINSCORE_ALERT", log, 0.1f); foreach (var tpd in tpds) { string slackMsg = ""; if (tpd.Score > minScoreBLAlert) { slackMsg += $"@channel\n"; } slackMsg += $"{tpd.FullText}\n" + $"Score (v{AzTwitterSarVersion.get()}): {tpd.Score.ToString("F", CultureInfo.InvariantCulture)}, " + $"ML ({tpd.VersionML}): {tpd.ScoreML.ToString("F", CultureInfo.InvariantCulture)}\n" + $"Link: http://twitter.com/politivest/status/{tpd.IdStr}"; log.LogInformation($"Message: {slackMsg}"); int sendResult = await SlackClient.PostSlackMessageAsync(log, slackMsg); log.LogInformation($"Message posted to slack, result: {sendResult}"); } log.LogInformation($"A_PublishTweets: Done."); return(0); }
public static async Task <string> MainOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log) { DateTime startTime = context.CurrentUtcDateTime; if (!context.IsReplaying) { log.LogInformation($"Main orchestrator (v{AzTwitterSarVersion.get()}), start time {startTime}. Call activity: GetTweets"); } string lastTweetId = context.GetInput <string>(); // 1) Get tweets from Twitter API List <TweetProcessingData> tweetData = await context.CallActivityAsync <List <TweetProcessingData> >( "A_GetTweets", lastTweetId); // The most likely case is that there are NO new tweets, so we provide // the short circuit which skips all the processing in this block, and // thus avoids a lot of replaying by the durable function mechanism. if (tweetData.Count > 0) { if (!context.IsReplaying) { log.LogInformation($"Got {tweetData.Count} new tweets; enter processing sub-orchestration."); } // 2) Process tweets one by one to find interesting ones. var parallelScoringTasks = new List <Task <TweetProcessingData> >(); foreach (var tpd in tweetData) // processes in order { if (!context.IsReplaying) { log.LogInformation($"Call sub-orchestration: P_ProcessTweet for tweet: {tpd.IdStr}"); } Task <TweetProcessingData> processTask = context.CallSubOrchestratorAsync <TweetProcessingData>( "P_ProcessTweet", tpd); parallelScoringTasks.Add(processTask); } await Task.WhenAll(parallelScoringTasks); // Sort the list of analyzed tweets by ascending id (chronologically). List <TweetProcessingData> logList = (from pt in parallelScoringTasks orderby Int64.Parse(pt.Result.IdStr) select pt.Result).ToList(); // Find the tweets that shall be published, chronological order. List <TweetProcessingData> publishList = ( from tpd in logList where tpd.ShallBePublished orderby Int64.Parse(tpd.IdStr) select tpd).ToList(); // Parallel section for postprocessing tasks. { if (!context.IsReplaying) { log.LogInformation($"Publishing {publishList.Count} tweets; logging {logList.Count} tweets."); } List <Task <int> > parallelPostprocessingTasks = new List <Task <int> >(); // We know there is something in the log list, but publishing we // trigger only if there is something to do for this activity. if (publishList.Count > 0) { parallelPostprocessingTasks.Add(context.CallActivityAsync <int>("A_PublishTweets", publishList)); } parallelPostprocessingTasks.Add(context.CallActivityAsync <int>("A_LogTweets", logList)); await Task.WhenAll(parallelPostprocessingTasks); } // We know there has been >= 1 tweet, so we update the last seen id, // which is passed to the next call. lastTweetId = logList[logList.Count - 1].IdStr; } else { if (!context.IsReplaying) { log.LogInformation($"Got no new tweets."); } } DateTime currentTime = context.CurrentUtcDateTime; int delaySeconds = GetDelaySeconds(context, log, startTime, currentTime); if (!context.IsReplaying) { log.LogInformation($"Determined delay: {delaySeconds} seconds after current time {currentTime}."); } if (delaySeconds > 0) { DateTime nextTime = currentTime.AddSeconds(delaySeconds); if (!context.IsReplaying) { log.LogInformation($"Setting wakeup time: {nextTime}."); } await context.CreateTimer(nextTime, CancellationToken.None); context.ContinueAsNew(lastTweetId); } return(lastTweetId); }