public void LogFunctionStarted(FunctionInstanceSnapshot snapshot) { // Which operation to run depends on whether or not the entity currently exists in the "queued" status. IConcurrentDocument <FunctionInstanceSnapshot> existingSnapshot = _store.Read(GetId(snapshot)); bool previouslyQueued; // If the existing entity doesn't contain a StartTime, it must be in the "queued" status. if (existingSnapshot != null && existingSnapshot.Document != null && !existingSnapshot.Document.StartTime.HasValue) { previouslyQueued = true; } else { previouslyQueued = false; } if (!previouslyQueued) { LogFunctionStartedWhenNotPreviouslyQueued(snapshot); } else { LogFunctionStartedWhenPreviouslyQueued(snapshot, existingSnapshot.ETag); } }
public static Dictionary <string, string> CreateMetadata(FunctionInstanceSnapshot snapshot) { if (snapshot == null) { throw new ArgumentNullException("snapshot"); } var metadata = new Dictionary <string, string>(); AddMetadataGuid(metadata, IdKey, snapshot.Id); AddMetadataString(metadata, DisplayTitleKey, snapshot.DisplayTitle); AddMetadataNullableDateTimeOffset(metadata, StartTimeKey, snapshot.StartTime); AddMetadataNullableDateTimeOffset(metadata, EndTimeKey, snapshot.EndTime); AddMetadataNullableBoolean(metadata, SucceededKey, snapshot.Succeeded); HeartbeatDescriptor heartbeat = snapshot.Heartbeat; if (heartbeat != null) { AddMetadataString(metadata, HeartbeatSharedContainerNameKey, heartbeat.SharedContainerName); AddMetadataString(metadata, HeartbeatSharedDirectoryNameKey, heartbeat.SharedDirectoryName); AddMetadataString(metadata, HeartbeatInstanceBlobNameKey, heartbeat.InstanceBlobName); AddMetadataInt32(metadata, HeartbeatExpirationInSecondsKey, heartbeat.ExpirationInSeconds); } return(metadata); }
public void LogFunctionStarted(FunctionInstanceSnapshot snapshot) { // Which operation to run depends on whether or not the entity currently exists in the "queued" status. IConcurrentDocument<FunctionInstanceSnapshot> existingSnapshot = _store.Read(GetId(snapshot)); bool previouslyQueued; // If the existing entity doesn't contain a StartTime, it must be in the "queued" status. if (existingSnapshot != null && existingSnapshot.Document != null && !existingSnapshot.Document.StartTime.HasValue) { previouslyQueued = true; } else { previouslyQueued = false; } if (!previouslyQueued) { LogFunctionStartedWhenNotPreviouslyQueued(snapshot); } else { LogFunctionStartedWhenPreviouslyQueued(snapshot, existingSnapshot.ETag); } }
public void LogFunctionQueued(FunctionInstanceSnapshot snapshot) { // Ignore the return result. Only the dashboard calls this method, and it does so before enqueuing the // message to the host to run the function. So realistically the blob can't already exist. And even if the // host did see the message before this call, an existing blob just means something more recent than // "queued" status, so there's nothing to do here in that case anyway. _store.TryCreate(GetId(snapshot), snapshot); }
private void LogFunctionStartedWhenNotPreviouslyQueued(FunctionInstanceSnapshot snapshot) { // LogFunctionStarted and LogFunctionCompleted may run concurrently. Ensure LogFunctionStarted loses by just // doing a simple Insert that will fail if the entity already exists. LogFunctionCompleted wins by having it // replace the LogFunctionStarted record, if any. // Ignore the return value: if the item already exists, LogFunctionCompleted already ran, so there's no work // to do here. _store.TryCreate(GetId(snapshot), snapshot); }
public void CreateOrUpdate(FunctionInstanceSnapshot snapshot, DateTimeOffset timestamp) { if (snapshot == null) { throw new ArgumentNullException("snapshot"); } string innerId = CreateInnerId(timestamp, snapshot.Id); _store.CreateOrUpdate(innerId, RecentInvocationEntry.CreateMetadata(snapshot), String.Empty); }
private void LogFunctionStartedWhenPreviouslyQueued(FunctionInstanceSnapshot snapshot, string etag) { // LogFunctionStarted and LogFunctionCompleted may run concurrently. LogFunctionQueued does not run // concurrently. Ensure LogFunctionStarted wins over LogFunctionQueued but loses to LogFunctionCompleted by // doing a Replace with ETag check that will fail if the entity has been changed. // LogFunctionCompleted wins by doing a Replace without an ETag check, so it will replace the // LogFunctionStarted (or Queued) record, if any. // Ignore the return value: if the ETag doesn't match, LogFunctionCompleted already ran, so there's no work // to do here. _store.TryUpdate(GetId(snapshot), etag, snapshot); }
internal InvocationLogViewModel(FunctionInstanceSnapshot snapshot, bool? heartbeatIsValid) { Id = snapshot.Id; FunctionName = snapshot.FunctionShortName; FunctionId = snapshot.FunctionId; FunctionFullName = snapshot.FunctionFullName; FunctionDisplayTitle = snapshot.DisplayTitle; HostInstanceId = snapshot.HostInstanceId; InstanceQueueName = snapshot.InstanceQueueName; if (snapshot.WebSiteName != null && snapshot.WebSiteName == Environment.GetEnvironmentVariable(WebSitesKnownKeyNames.WebSiteNameKey)) { ExecutingJobRunId = new WebJobRunIdentifierViewModel((WebJobType)Enum.Parse(typeof(WebJobType), snapshot.WebJobType), snapshot.WebJobName, snapshot.WebJobRunId); } if (heartbeatIsValid.HasValue) { Status = snapshot.GetStatusWithHeartbeat(heartbeatIsValid.Value); } else { Status = snapshot.GetStatusWithoutHeartbeat(); } switch (Status) { case FunctionInstanceStatus.Running: WhenUtc = snapshot.StartTime.Value.UtcDateTime; Duration = DateTimeOffset.UtcNow - snapshot.StartTime; break; case FunctionInstanceStatus.CompletedSuccess: WhenUtc = snapshot.EndTime.Value.UtcDateTime; Duration = snapshot.GetFinalDuration(); break; case FunctionInstanceStatus.CompletedFailed: WhenUtc = snapshot.EndTime.Value.UtcDateTime; Duration = snapshot.GetFinalDuration(); ExceptionType = snapshot.ExceptionType; ExceptionMessage = snapshot.ExceptionMessage; break; case FunctionInstanceStatus.NeverFinished: WhenUtc = snapshot.StartTime.Value.UtcDateTime; Duration = null; break; } }
internal TriggerReasonViewModel(FunctionInstanceSnapshot underlyingObject) { UnderlyingObject = underlyingObject; }
private static ParameterModel[] CreateParameterModels(CloudStorageAccount account, FunctionInstanceSnapshot snapshot) { List<ParameterModel> models = new List<ParameterModel>(); IDictionary<string, FunctionInstanceArgument> parameters = snapshot.Arguments; IDictionary<string, ParameterLog> parameterLogs = LogAnalysis.GetParameterLogs(account, snapshot); foreach (KeyValuePair<string, FunctionInstanceArgument> parameter in parameters) { string name = parameter.Key; FunctionInstanceArgument argument = parameter.Value; ParameterLog log; if (parameterLogs != null && parameterLogs.ContainsKey(name)) { log = parameterLogs[name]; } else { log = null; } LogAnalysis.AddParameterModels(name, argument, log, snapshot, models); } return models.ToArray(); }
internal static BlobBoundParameterModel CreateExtendedBlobModel(FunctionInstanceSnapshot snapshot, FunctionInstanceArgument argument) { Debug.Assert(argument != null); if (argument.Value == null) { return null; } string[] components = argument.Value.Split(new char[] { '/' }); if (components.Length != 2) { return null; } var blobParam = new BlobBoundParameterModel(); blobParam.IsOutput = argument.IsBlobOutput; blobParam.ConnectionStringKey = ConnectionStringProvider.GetPrefixedConnectionStringName(argument.AccountName); CloudStorageAccount account = argument.GetStorageAccount(); if (account == null) { blobParam.IsConnectionStringMissing = true; return blobParam; } CloudBlockBlob blob = account .CreateCloudBlobClient() .GetContainerReference(components[0]) .GetBlockBlobReference(components[1]); Guid? blobWriter = GetBlobWriter(blob); if (!blobWriter.HasValue) { blobParam.IsBlobMissing = true; } else { blobParam.OwnerId = blobWriter.Value; if (blobWriter.Value == snapshot.Id) { blobParam.IsBlobOwnedByCurrentFunctionInstance = true; } } return blobParam; }
private static ParameterModel[] CreateParameterModels(CloudStorageAccount account, FunctionInstanceSnapshot snapshot) { List<ParameterModel> models = new List<ParameterModel>(); // It's important that we order any virtual parameters (e.g. Singleton parameters) to the end // so they don't interfere with actual function parameter ordering var parameters = snapshot.Arguments.OrderBy(p => p.Value.IsVirtualParameter); IDictionary<string, ParameterLog> parameterLogs = LogAnalysis.GetParameterLogs(account, snapshot); foreach (KeyValuePair<string, FunctionInstanceArgument> parameter in parameters) { string name = parameter.Key; FunctionInstanceArgument argument = parameter.Value; ParameterLog log; if (parameterLogs != null && parameterLogs.ContainsKey(name)) { log = parameterLogs[name]; } else { log = null; } LogAnalysis.AddParameterModels(name, argument, log, snapshot, models); } return models.ToArray(); }
public void CreateOrUpdate(FunctionInstanceSnapshot snapshot, DateTimeOffset timestamp) { string innerId = CreateInnerId(snapshot.ParentId.Value, timestamp, snapshot.Id); _store.CreateOrUpdate(innerId, RecentInvocationEntry.CreateMetadata(snapshot), String.Empty); }
private static bool TryResolveParameters(FunctionSnapshot function, FunctionInstanceSnapshot snapshot, out IEnumerable<FunctionParameterViewModel> resolvedParameters) { List<FunctionParameterViewModel> parameters = new List<FunctionParameterViewModel>(); foreach (KeyValuePair<string, ParameterSnapshot> parameter in function.Parameters) { if (!snapshot.Arguments.ContainsKey(parameter.Key)) { resolvedParameters = null; return false; } FunctionParameterViewModel parameterModel = new FunctionParameterViewModel { Name = parameter.Key, Description = parameter.Value.Prompt, Value = snapshot.Arguments[parameter.Key].Value }; parameters.Add(parameterModel); } resolvedParameters = parameters; return true; }
private FunctionSnapshot GetFunctionFromInstance(string id, out Guid parsed, out FunctionInstanceSnapshot snapshot) { if (!Guid.TryParse(id, out parsed)) { snapshot = null; return null; } snapshot = _functionInstanceLookup.Lookup(parsed); if (snapshot == null) { return null; } return GetFunction(snapshot.FunctionId); }
private bool? HostInstanceHasHeartbeat(FunctionInstanceSnapshot snapshot) { HeartbeatDescriptor heartbeat = snapshot.Heartbeat; if (heartbeat == null) { return null; } return HostInstanceHasHeartbeat(heartbeat.SharedContainerName, heartbeat.SharedDirectoryName, heartbeat.InstanceBlobName, heartbeat.ExpirationInSeconds); }
public void LogFunctionCompleted(FunctionInstanceSnapshot snapshot) { // LogFunctionStarted and LogFunctionCompleted may run concurrently. Ensure LogFunctionCompleted wins by // having it replace the LogFunctionStarted record, if any. _store.CreateOrUpdate(GetId(snapshot), snapshot); }
private static string GetId(FunctionInstanceSnapshot snapshot) { return snapshot.Id.ToString("N"); }
private static string GetId(FunctionInstanceSnapshot snapshot) { return(snapshot.Id.ToString("N")); }
public void CreateOrUpdate(FunctionInstanceSnapshot snapshot, WebJobRunIdentifier webJobRunId, DateTimeOffset timestamp) { string innerId = CreateInnerId(webJobRunId, timestamp, snapshot.Id); _store.CreateOrUpdate(innerId, RecentInvocationEntry.CreateMetadata(snapshot), String.Empty); }
private InvocationLogViewModel CreateInvocationEntry(RecentInvocationEntry entry) { Debug.Assert(entry != null); var metadataSnapshot = new FunctionInstanceSnapshot(); metadataSnapshot.Id = entry.Id; metadataSnapshot.DisplayTitle = entry.DisplayTitle; metadataSnapshot.StartTime = entry.StartTime; metadataSnapshot.EndTime = entry.EndTime; metadataSnapshot.Succeeded = entry.Succeeded; metadataSnapshot.Heartbeat = entry.Heartbeat; return new InvocationLogViewModel(metadataSnapshot, HostInstanceHasHeartbeat(metadataSnapshot)); }
public void FunctionInstanceSnapshot_BuildDisplayTitle_CompletelyRemovesLineBreaks(string argumentValue, string expectedDisplayTitle) { FunctionInstanceSnapshot message = new FunctionInstanceSnapshot { Arguments = new Dictionary<string, FunctionInstanceArgument> { { "message", new FunctionInstanceArgument() { Value = argumentValue } } }, }; string displayTitle = message.DisplayTitle; Assert.Equal(expectedDisplayTitle, displayTitle); Assert.DoesNotContain("\r", displayTitle); Assert.DoesNotContain("\n", displayTitle); }
// Get Live information from current watcher values. internal static IDictionary<string, ParameterLog> GetParameterLogs(CloudStorageAccount account, FunctionInstanceSnapshot snapshot) { if (snapshot.ParameterLogs != null) { return snapshot.ParameterLogs; } if (snapshot.ParameterLogBlob == null) { return null; } CloudBlockBlob blob = snapshot.ParameterLogBlob.GetBlockBlob(account); string contents; try { contents = blob.DownloadText(); } catch (StorageException exception) { // common case, no status information written. if (exception.IsNotFound()) { return null; } else { throw; } } try { return JsonConvert.DeserializeObject<IDictionary<string, ParameterLog>>(contents, JsonSerialization.Settings); } catch { // Not fatal. // This could happen if the app wrote a corrupted log. return null; } }
public static void AddParameterModels(string parameterName, FunctionInstanceArgument argument, ParameterLog log, FunctionInstanceSnapshot snapshot, ICollection<ParameterModel> parameterModels) { if (argument == null) { throw new ArgumentNullException("argument"); } if (parameterModels == null) { throw new ArgumentNullException("parameterModels"); } ParameterModel model = new ParameterModel { Name = parameterName, ArgInvokeString = argument.Value }; if (log != null) { model.Status = Format(log); } if (argument.IsBlob) { model.ExtendedBlobModel = LogAnalysis.CreateExtendedBlobModel(snapshot, argument); } parameterModels.Add(model); // Special-case IBinder, which adds sub-parameters. BinderParameterLog binderLog = log as BinderParameterLog; if (binderLog != null) { IEnumerable<BinderParameterLogItem> items = binderLog.Items; if (items != null) { int count = items.Count(); model.Status = String.Format(CultureInfo.CurrentCulture, "Bound {0} object{1}.", count, count != 1 ? "s" : String.Empty); foreach (BinderParameterLogItem item in items) { if (item == null) { continue; } ParameterSnapshot itemSnapshot = HostIndexer.CreateParameterSnapshot(item.Descriptor); string itemName = parameterName; if (!string.IsNullOrEmpty(itemSnapshot.AttributeText)) { itemName += ": " + itemSnapshot.AttributeText; } FunctionInstanceArgument itemArgument = FunctionIndexer.CreateFunctionInstanceArgument(item.Value, item.Descriptor); AddParameterModels(itemName, itemArgument, item.Log, snapshot, parameterModels); } } } }
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 static Dictionary<string, string> CreateMetadata(FunctionInstanceSnapshot snapshot) { if (snapshot == null) { throw new ArgumentNullException("snapshot"); } var metadata = new Dictionary<string, string>(); AddMetadataGuid(metadata, IdKey, snapshot.Id); AddMetadataString(metadata, DisplayTitleKey, snapshot.DisplayTitle); AddMetadataNullableDateTimeOffset(metadata, StartTimeKey, snapshot.StartTime); AddMetadataNullableDateTimeOffset(metadata, EndTimeKey, snapshot.EndTime); AddMetadataNullableBoolean(metadata, SucceededKey, snapshot.Succeeded); HeartbeatDescriptor heartbeat = snapshot.Heartbeat; if (heartbeat != null) { AddMetadataString(metadata, HeartbeatSharedContainerNameKey, heartbeat.SharedContainerName); AddMetadataString(metadata, HeartbeatSharedDirectoryNameKey, heartbeat.SharedDirectoryName); AddMetadataString(metadata, HeartbeatInstanceBlobNameKey, heartbeat.InstanceBlobName); AddMetadataInt32(metadata, HeartbeatExpirationInSecondsKey, heartbeat.ExpirationInSeconds); } return metadata; }