// 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); } }
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); }
// 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); } }
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); } }
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)); }
IResultSegment <RecentInvocationEntry> IRecentInvocationIndexByJobRunReader.Read(WebJobRunIdentifier webJobRunId, int maximumResults, string continuationToken) { var x = new RecentInvocationEntry[0]; return(new ResultSegment <RecentInvocationEntry>(x, null)); }
private static string CreateInnerId(WebJobRunIdentifier webJobRunId, DateTimeOffset timestamp, Guid id) { return(DashboardBlobPrefixes.CreateByJobRunRelativePrefix(webJobRunId) + RecentInvocationEntry.CreateBlobName(timestamp, id)); }
public void DeleteIfExists(WebJobRunIdentifier webJobRunId, DateTimeOffset timestamp, Guid id) { string innerId = CreateInnerId(webJobRunId, timestamp, id); _store.DeleteIfExists(innerId); }
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); }
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); } }
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 static string CreateInnerId(WebJobRunIdentifier webJobRunId, DateTimeOffset timestamp, Guid id) { return DashboardBlobPrefixes.CreateByJobRunRelativePrefix(webJobRunId) + RecentInvocationEntry.CreateBlobName(timestamp, id); }