Beispiel #1
0
        // This method runs concurrently with other index processing.
        // Ensure all logic here is idempotent.
        public void ProcessFunctionStarted(FunctionStartedMessage message)
        {
            FunctionInstanceSnapshot snapshot = CreateSnapshot(message);

            _functionInstanceLogger.LogFunctionStarted(snapshot);

            string              functionId         = new FunctionIdentifier(message.SharedQueueName, message.Function.Id).ToString();
            Guid                functionInstanceId = message.FunctionInstanceId;
            DateTimeOffset      startTime          = message.StartTime;
            WebJobRunIdentifier webJobRunId        = message.WebJobRunIdentifier;
            Guid?               parentId           = message.ParentId;

            // Race to write index entries for function started.
            if (!HasLoggedFunctionCompleted(functionInstanceId))
            {
                CreateOrUpdateIndexEntries(snapshot, startTime, webJobRunId);
            }

            // If the function has since completed, we lost the race.
            // Delete any function started index entries.
            // Note that this code does not depend on whether or not the index entries were previously written by this
            // method, as this processing could have been aborted and resumed at another point in time. In that case,
            // we still own cleaning up any dangling function started index entries.
            DateTimeOffset?functionCompletedTime      = GetFunctionCompletedTime(functionInstanceId);
            bool           hasLoggedFunctionCompleted = functionCompletedTime.HasValue;

            if (hasLoggedFunctionCompleted)
            {
                DeleteFunctionStartedIndexEntriesIfNeeded(functionInstanceId, message.StartTime,
                                                          functionCompletedTime.Value, functionId, parentId, webJobRunId);
            }
        }
Beispiel #2
0
        public IResultSegment <RecentInvocationEntry> Read(WebJobRunIdentifier webJobRunId, int maximumResults,
                                                           string continuationToken)
        {
            string relativePrefix = DashboardBlobPrefixes.CreateByJobRunRelativePrefix(webJobRunId);

            return(_innerReader.Read(relativePrefix, maximumResults, continuationToken));
        }
        public void CreateOrUpdate(FunctionInstanceSnapshot snapshot, WebJobRunIdentifier webJobRunId, DateTimeOffset timestamp)
        {
            if (snapshot == null)
            {
                throw new ArgumentNullException("snapshot");
            }

            string innerId = CreateInnerId(webJobRunId, timestamp, snapshot.Id);
            _store.CreateOrUpdate(innerId, RecentInvocationEntry.CreateMetadata(snapshot), String.Empty);
        }
        public void CreateOrUpdate(FunctionInstanceSnapshot snapshot, WebJobRunIdentifier webJobRunId, DateTimeOffset timestamp)
        {
            if (snapshot == null)
            {
                throw new ArgumentNullException("snapshot");
            }

            string innerId = CreateInnerId(webJobRunId, timestamp, snapshot.Id);

            _store.CreateOrUpdate(innerId, RecentInvocationEntry.CreateMetadata(snapshot), String.Empty);
        }
        // This method runs concurrently with other index processing.
        // Ensure all logic here is idempotent.
        public void ProcessFunctionCompleted(FunctionCompletedMessage message)
        {
            if (message == null)
            {
                throw new ArgumentNullException("message");
            }

            FunctionInstanceSnapshot snapshot = CreateSnapshot(message);

            // The completed message includes the full parameter logs; delete the extra blob used for running status
            // updates.
            DeleteParameterLogBlob(snapshot.ParameterLogBlob);
            snapshot.ParameterLogBlob = null;

            _functionInstanceLogger.LogFunctionCompleted(snapshot);

            Guid                functionInstanceId = message.FunctionInstanceId;
            DateTimeOffset      endTime            = message.EndTime;
            string              functionId         = new FunctionIdentifier(message.SharedQueueName, message.Function.Id).ToString();
            Guid?               parentId           = message.ParentId;
            WebJobRunIdentifier webJobRunId        = message.WebJobRunIdentifier;

            DeleteFunctionStartedIndexEntriesIfNeeded(functionInstanceId, message.StartTime, endTime, functionId,
                                                      parentId, webJobRunId);

            CreateOrUpdateIndexEntries(snapshot, endTime, webJobRunId);

            // Increment is non-idempotent. If the process dies before deleting the message that triggered it, it can
            // occur multiple times.
            // If we wanted to make this operation idempotent, one option would be to store the list of function
            // instance IDs that succeeded & failed, rather than just the counters, so duplicate operations could be
            // detected.
            // For now, we just do a non-idempotent increment last, which makes it very unlikely that the queue message
            // would not subsequently get deleted.
            if (message.Succeeded)
            {
                _statisticsWriter.IncrementSuccess(functionId);
            }
            else
            {
                _statisticsWriter.IncrementFailure(functionId);
            }
        }
Beispiel #6
0
        static WebJobRunIdentifier()
        {
            var webSiteName = Environment.GetEnvironmentVariable(WebSitesKnownKeyNames.WebSiteNameKey);
            var jobName     = Environment.GetEnvironmentVariable(WebSitesKnownKeyNames.JobNameKey);
            var jobTypeName = Environment.GetEnvironmentVariable(WebSitesKnownKeyNames.JobTypeKey);
            var jobRunId    = Environment.GetEnvironmentVariable(WebSitesKnownKeyNames.JobRunIdKey);

            WebJobTypes webJobType;
            var         isValidWebJobType = Enum.TryParse(jobTypeName, true, out webJobType);

            if (webSiteName == null || !isValidWebJobType || jobName == null)
            {
                _current = null;
            }
            else
            {
                _current = new WebJobRunIdentifier(webSiteName, webJobType, jobName, jobRunId);
            }
        }
        static WebJobRunIdentifier()
        {
            var webSiteName = Environment.GetEnvironmentVariable(WebSitesKnownKeyNames.WebSiteNameKey);
            var jobName = Environment.GetEnvironmentVariable(WebSitesKnownKeyNames.JobNameKey);
            var jobTypeName = Environment.GetEnvironmentVariable(WebSitesKnownKeyNames.JobTypeKey);
            var jobRunId = Environment.GetEnvironmentVariable(WebSitesKnownKeyNames.JobRunIdKey);

            WebJobTypes webJobType;
            var isValidWebJobType = Enum.TryParse(jobTypeName, true, out webJobType);

            if (webSiteName == null || !isValidWebJobType || jobName == null)
            {
                Current = null;
            }
            else
            {
                Current = new WebJobRunIdentifier(webSiteName, webJobType, jobName, jobRunId);
            }
        }
Beispiel #8
0
        private IHttpActionResult GetFunctionsInJob(WebJobTypes webJobType, string jobName, string runId, [FromUri] PagingInfo pagingInfo)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest(ModelState));
            }

            if (pagingInfo == null)
            {
                return(BadRequest());
            }

            var runIdentifier = new WebJobRunIdentifier(Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME"),
                                                        (InternalWebJobTypes)webJobType, jobName, runId);

            IResultSegment <RecentInvocationEntry> indexSegment = _recentInvocationsByJobRunReader.Read(runIdentifier,
                                                                                                        pagingInfo.Limit, pagingInfo.ContinuationToken);
            InvocationLogSegment results;

            if (indexSegment != null)
            {
                results = new InvocationLogSegment
                {
                    Entries           = CreateInvocationEntries(indexSegment.Results),
                    ContinuationToken = indexSegment.ContinuationToken
                };
            }
            else
            {
                results = new InvocationLogSegment
                {
                    IsOldHost = OnlyBeta1HostExists(alreadyFoundNoNewerEntries: false)
                };
            }

            return(Ok(results));
        }
Beispiel #9
0
        IResultSegment <RecentInvocationEntry> IRecentInvocationIndexByJobRunReader.Read(WebJobRunIdentifier webJobRunId, int maximumResults, string continuationToken)
        {
            var x = new RecentInvocationEntry[0];

            return(new ResultSegment <RecentInvocationEntry>(x, null));
        }
Beispiel #10
0
 private static string CreateInnerId(WebJobRunIdentifier webJobRunId, DateTimeOffset timestamp, Guid id)
 {
     return(DashboardBlobPrefixes.CreateByJobRunRelativePrefix(webJobRunId) +
            RecentInvocationEntry.CreateBlobName(timestamp, id));
 }
Beispiel #11
0
        public void DeleteIfExists(WebJobRunIdentifier webJobRunId, DateTimeOffset timestamp, Guid id)
        {
            string innerId = CreateInnerId(webJobRunId, timestamp, id);

            _store.DeleteIfExists(innerId);
        }
Beispiel #12
0
        public void CreateOrUpdate(FunctionInstanceSnapshot snapshot, WebJobRunIdentifier webJobRunId, DateTimeOffset timestamp)
        {
            string innerId = CreateInnerId(webJobRunId, timestamp, snapshot.Id);

            _store.CreateOrUpdate(innerId, RecentInvocationEntry.CreateMetadata(snapshot), String.Empty);
        }
 public IResultSegment<RecentInvocationEntry> Read(WebJobRunIdentifier webJobRunId, int maximumResults, string continuationToken)
 {
     string relativePrefix = DashboardBlobPrefixes.CreateByJobRunRelativePrefix(webJobRunId);
     return _innerReader.Read(relativePrefix, maximumResults, continuationToken);
 }
Beispiel #14
0
 public static string CreateByJobRunRelativePrefix(WebJobRunIdentifier webJobRunId)
 {
     return(webJobRunId.GetKey() + "/");
 }
        private IHttpActionResult GetFunctionsInJob(WebJobTypes webJobType, string jobName, string runId, [FromUri] PagingInfo pagingInfo)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            if (pagingInfo == null)
            {
                return BadRequest();
            }

            var runIdentifier = new WebJobRunIdentifier(Environment.GetEnvironmentVariable("WEBSITE_SITE_NAME"),
                (InternalWebJobTypes)webJobType, jobName, runId);

            IResultSegment<RecentInvocationEntry> indexSegment = _recentInvocationsByJobRunReader.Read(runIdentifier,
                pagingInfo.Limit, pagingInfo.ContinuationToken);
            InvocationLogSegment results;

            if (indexSegment != null)
            {
                results = new InvocationLogSegment
                {
                    Entries = CreateInvocationEntries(indexSegment.Results),
                    ContinuationToken = indexSegment.ContinuationToken
                };
            }
            else
            {
                results = new InvocationLogSegment
                {
                    IsOldHost = OnlyBeta1HostExists(alreadyFoundNoNewerEntries: false)
                };
            }

            return Ok(results);
        }
 public static string CreateByJobRunRelativePrefix(WebJobRunIdentifier webJobRunId)
 {
     return webJobRunId.GetKey() + "/";
 }
        private void DeleteFunctionStartedIndexEntriesIfNeeded(Guid functionInstanceId, DateTimeOffset startTime,
                                                               DateTimeOffset endTime, string functionId, Guid?parentId, WebJobRunIdentifier webJobRunId)
        {
            if (startTime.UtcDateTime.Ticks != endTime.UtcDateTime.Ticks)
            {
                _recentInvocationsWriter.DeleteIfExists(startTime, functionInstanceId);
                _recentInvocationsByFunctionWriter.DeleteIfExists(functionId, startTime, functionInstanceId);

                if (parentId.HasValue)
                {
                    _recentInvocationsByParentWriter.DeleteIfExists(parentId.Value, startTime, functionInstanceId);
                }

                if (webJobRunId != null)
                {
                    _recentInvocationsByJobRunWriter.DeleteIfExists(webJobRunId, startTime, functionInstanceId);
                }
            }
        }
        private void CreateOrUpdateIndexEntries(FunctionInstanceSnapshot snapshot, DateTimeOffset timestamp, WebJobRunIdentifier webJobRunId)
        {
            _recentInvocationsWriter.CreateOrUpdate(snapshot, timestamp);
            _recentInvocationsByFunctionWriter.CreateOrUpdate(snapshot, timestamp);

            if (webJobRunId != null)
            {
                _recentInvocationsByJobRunWriter.CreateOrUpdate(snapshot, webJobRunId, timestamp);
            }

            if (snapshot.ParentId.HasValue)
            {
                _recentInvocationsByParentWriter.CreateOrUpdate(snapshot, timestamp);
            }
        }
 public void DeleteIfExists(WebJobRunIdentifier webJobRunId, DateTimeOffset timestamp, Guid id)
 {
     string innerId = CreateInnerId(webJobRunId, timestamp, id);
     _store.DeleteIfExists(innerId);
 }
        private void DeleteFunctionStartedIndexEntriesIfNeeded(Guid functionInstanceId, DateTimeOffset startTime,
            DateTimeOffset endTime, string functionId, Guid? parentId, WebJobRunIdentifier webJobRunId)
        {
            if (startTime.UtcDateTime.Ticks != endTime.UtcDateTime.Ticks)
            {
                _recentInvocationsWriter.DeleteIfExists(startTime, functionInstanceId);
                _recentInvocationsByFunctionWriter.DeleteIfExists(functionId, startTime, functionInstanceId);

                if (parentId.HasValue)
                {
                    _recentInvocationsByParentWriter.DeleteIfExists(parentId.Value, startTime, functionInstanceId);
                }

                if (webJobRunId != null)
                {
                    _recentInvocationsByJobRunWriter.DeleteIfExists(webJobRunId, startTime, functionInstanceId);
                }
            }
        }
 IResultSegment<RecentInvocationEntry> IRecentInvocationIndexByJobRunReader.Read(WebJobRunIdentifier webJobRunId, int maximumResults, string continuationToken)
 {
     var x = new RecentInvocationEntry[0];
     return new ResultSegment<RecentInvocationEntry>(x, null);
 }
        private void CreateOrUpdateIndexEntries(FunctionInstanceSnapshot snapshot, DateTimeOffset timestamp, WebJobRunIdentifier webJobRunId)
        {
            _recentInvocationsWriter.CreateOrUpdate(snapshot, timestamp);
            _recentInvocationsByFunctionWriter.CreateOrUpdate(snapshot, timestamp);

            if (webJobRunId != null)
            {
                _recentInvocationsByJobRunWriter.CreateOrUpdate(snapshot, webJobRunId, timestamp);
            }

            if (snapshot.ParentId.HasValue)
            {
                _recentInvocationsByParentWriter.CreateOrUpdate(snapshot, timestamp);
            }
        }
 private static string CreateInnerId(WebJobRunIdentifier webJobRunId, DateTimeOffset timestamp, Guid id)
 {
     return DashboardBlobPrefixes.CreateByJobRunRelativePrefix(webJobRunId) +
         RecentInvocationEntry.CreateBlobName(timestamp, id);
 }