예제 #1
0
        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);
        }
예제 #2
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);
        }