public static async Task <bool> Transfer( [OrchestrationTrigger] IDurableOrchestrationContext context) { var transferOperation = context.GetInput <TransferOperation>(); bool transferSuccessful = false; EntityId fromAccountId = new EntityId(nameof(Account), transferOperation.FromAccountId); EntityId toAccountId = new EntityId(nameof(Account), transferOperation.ToAccountId); using (await context.LockAsync(fromAccountId, toAccountId)) { var fromAccountBalance = await context.CallEntityAsync <int>(fromAccountId, "balance"); if (fromAccountBalance >= transferOperation.Amount) { var taskList = new List <Task>(); taskList.Add(context.CallEntityAsync <int>(fromAccountId, "withdraw", transferOperation.Amount)); taskList.Add(context.CallEntityAsync <int>(toAccountId, "deposit", transferOperation.Amount)); await Task.WhenAll(taskList.ToArray()); transferSuccessful = true; } } return(transferSuccessful); }
#pragma warning restore 618 public static async Task <string> SignalAndCallStringStore([OrchestrationTrigger] IDurableOrchestrationContext ctx) { // construct entity id from entity name and a supplied GUID var entity = new EntityId("StringStore2", ctx.GetInput <Guid>().ToString()); // signal and call (both of these will be delivered close together) ctx.SignalEntity(entity, "set", "333"); var result = await ctx.CallEntityAsync <string>(entity, "get"); if (result != "333") { return($"fail: wrong entity state: expected 333, got {result}"); } // make another call to see if the state survives replay result = await ctx.CallEntityAsync <string>(entity, "get"); if (result != "333") { return($"fail: wrong entity state: expected 333, got {result}"); } return("ok"); }
public async Task <int> IncrementOrchestration( [OrchestrationTrigger] IDurableOrchestrationContext context) { var entityId = new EntityId(nameof(Counter), CounterName); await context.CallEntityAsync(entityId, "Add", 1); var counter = await context.CallEntityAsync <int>(entityId, "Get"); counter++; return(counter); }
public static async Task UpdateTwoCounters([OrchestrationTrigger] IDurableOrchestrationContext ctx) { var entity1 = new EntityId("CounterEntity", "1"); var entity2 = new EntityId("CounterEntity", "2"); using (await ctx.LockAsync(entity1, entity2)) { await Task.WhenAll( ctx.CallEntityAsync(entity1, "add", 42), ctx.CallEntityAsync(entity2, "add", -42)); } }
public async Task ProcessUserOrchestration([OrchestrationTrigger] IDurableOrchestrationContext context, ILogger logger) { //------------------------------------------------------------------------------------------------------------------------------------ // Get the user ID that will be processed in the current orchestration. var userId = context.GetInput <string>(); if (string.IsNullOrEmpty(userId)) { logger.LogError($"No user ID was passed as input to the '{context.Name}' orchestration running with instance ID '{context.InstanceId}'. The orchestration cannot continue and will now exit."); return; } //------------------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------------------ // Create a reference to the entity, and initialize the entity with the orchestration ID for the current instance. // This will make the current orchestration the current for handling processing of a given user, invalidating any other // running instance that has been started for the same user. var eid = new EntityId(Names.ProcessUserState, userId); await context.CallEntityAsync(eid, nameof(ProcessUserState.InitializeUserProcessing), context.InstanceId); //------------------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------------------ // Simulating some work performed in the orchestration to allow other orchestrations to be triggered while this is still running. await context.CallActivityAsync(Names.Delay, 5000); //------------------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------------------ // After we've done some processing, we check if the currently running orchestration is still the current orchestration for // the user that the orchestration is processing. We then make decisions based on the information returned from the entity. // We can repeat this process as many times we need in the orchestration, for instance if processing involves several steps that // call into sub orchestrations or activity functions. Whatever makes sense for your particular case. var isCurrent = await context.CallEntityAsync <bool>(eid, nameof(ProcessUserState.IsCurrentOrchestration), context.InstanceId); if (isCurrent) { logger.LogInformation($"The orchestration '{context.Name}' with instance '{context.InstanceId}' is still the current orchestration and will continue running."); } else { logger.LogWarning($"A newer orchestration instance of the orchestation '{context.Name}' for user ID '{userId}' has been started. This instance ('{context.InstanceId}') should not perform any processing anymore."); } //------------------------------------------------------------------------------------------------------------------------------------ }
public static async Task <(int, int)> LockedTransfer([OrchestrationTrigger] IDurableOrchestrationContext ctx) { var(from, to) = ctx.GetInput <(EntityId, EntityId)>(); if (from.Equals(to)) { throw new ArgumentException("from and to must be distinct"); } if (ctx.IsLocked(out _)) { throw new Exception("test failed: lock context is incorrect"); } int fromBalance; int toBalance; using (await ctx.LockAsync(from, to)) { if (!ctx.IsLocked(out var ownedLocks) || ownedLocks.Count != 2 || !ownedLocks.Contains(from) || !ownedLocks.Contains(to)) { throw new Exception("test failed: lock context is incorrect"); } // read balances in parallel var t1 = ctx.CallEntityAsync <int>(from, "get"); var t2 = ctx.CallEntityAsync <int>(to, "get"); fromBalance = await t1; toBalance = await t2; // modify fromBalance--; toBalance++; // write balances in parallel var t3 = ctx.CallEntityAsync(from, "set", fromBalance); var t4 = ctx.CallEntityAsync(to, "set", toBalance); await t3; await t4; } if (ctx.IsLocked(out _)) { throw new Exception("test failed: lock context is incorrect"); } return(fromBalance, toBalance); }
public async Task RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { await context.CallEntityAsync(new EntityId(nameof(RegistrationAggregate), context.InstanceId), nameof(RegistrationAggregate.Create), context.CurrentUtcDateTime); var finishRegistration = await context.WaitForExternalEvent(nameof(FinishRegistration), TimeSpan.FromMinutes(5), Status.TimeOut); await context.CallEntityAsync(new EntityId(nameof(RegistrationAggregate), context.InstanceId), nameof(RegistrationAggregate.SetState), new UpdateStatusCommand() { Status = finishRegistration, Time = context.CurrentUtcDateTime }); }
public static async Task PatchCard( [OrchestrationTrigger] IDurableOrchestrationContext context) { var entityOperation = context.GetInput <EntityOperation>(); await context.CallEntityAsync(entityOperation.EntityId, "Patch", entityOperation.Document); }
public static async Task <string> RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log) { string endpoint = context.GetInput <object>().ToString(); var request = new DurableHttpRequest(HttpMethod.Get, new Uri(endpoint)); DurableHttpResponse endpointResponse = await context.CallHttpAsync(request); if (endpointResponse.StatusCode != HttpStatusCode.OK) { throw new ArgumentException($"Failed to contact endpoint: {endpointResponse.StatusCode}: {endpointResponse.Content}"); } log.LogInformation($"Information retrieved from endpoint = {endpointResponse.Content}."); string[] words = endpointResponse.Content.Split(" "); log.LogInformation($"Words count = {words.Count()}."); var entityId = new EntityId("OrchestrationSample_Counter", "charCounter"); context.SignalEntity(entityId, "reset"); foreach (string word in words) { context.SignalEntity(entityId, "Add", word); } await context.CallActivityAsync("OrchestrationSample_LogBlob", endpoint.Replace("/", "bar")); int count = await context.CallEntityAsync <int>(entityId, "Get"); return($"Endpoint: {endpoint} has the total of {count} chars"); }
public static async Task <string> BasicObjects([OrchestrationTrigger] IDurableOrchestrationContext ctx) { var chatroom = ctx.GetInput <EntityId>(); // signals ctx.SignalEntity(chatroom, "post", "a"); ctx.SignalEntity(chatroom, "post", "b"); // call returning a task, but no result await ctx.CallEntityAsync(chatroom, "post", "c"); // calls returning a result var result = await ctx.CallEntityAsync <List <KeyValuePair <DateTime, string> > >(chatroom, "get"); return(string.Join(",", result.Select(kvp => kvp.Value))); }
public static async Task RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { var(userId, location) = context.GetInput <(string, int)>(); var userEntity = new EntityId(nameof(UserEntity), userId); // first, update the user information to advertise the location. await context.CallEntityAsync(userEntity, nameof(UserEntity.SetLocation), location); // next, try to match this user with // someone who has already advertised their location in a nearby region var nearbyRegions = ZipCodes.GetProximityList(location); foreach (var region in nearbyRegions) { var regionProxy = context.CreateEntityProxy <IRegionEntity>(region.ToString()); string[] candidates = await(userId.StartsWith("R") ? regionProxy.GetAvailableDrivers() : regionProxy.GetAvailableRiders()); foreach (var candidate in candidates) { if (await TryFinalizeMatch(userId, candidate, context)) { return; } } } // we could not find a match. // we will just wait until someone else finds us. }
public async Task SaveState([OrchestrationTrigger] IDurableOrchestrationContext context) { (string nonce, string state) = context.GetInput <(string, string)>(); EntityId nonceEntityId = new EntityId(nameof(Nonce), nonce); await context.CallEntityAsync(nonceEntityId, nameof(Nonce.SetState), state); }
public static async Task <string> LargeEntity([OrchestrationTrigger] IDurableOrchestrationContext ctx) { var entityId = ctx.GetInput <EntityId>(); string content = new string('.', 100000); await ctx.CallEntityAsync <int>(entityId, "set", content); var result = await ctx.CallEntityAsync <string>(entityId, "get"); if (result != content) { return($"fail: wrong entity state"); } return("ok"); }
public async Task OrchestratorAsync( [OrchestrationTrigger] IDurableOrchestrationContext context) { var entity = new EntityId("EntityState", "global"); using (await context.LockAsync(entity)) { var lastId = await context.CallEntityAsync <long>(entity, "Get"); var nextLastId = await context.CallActivityAsync <long>("TimerTrigger-Activity", lastId); if (lastId != nextLastId) { await context.CallEntityAsync(entity, "Set", nextLastId); } } }
public static async Task SignalAndCallChatRoom([OrchestrationTrigger] IDurableOrchestrationContext ctx) { var entity = new EntityId("ChatRoom", "myChat"); ctx.SignalEntity(entity, "Post", "Hello World"); var result = await ctx.CallEntityAsync <List <KeyValuePair <DateTime, string> > >(entity, "Get"); }
public async Task Orchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { var cIContext = context.GetInput <CIContext>(); // Get issues SearchIssue issues = await context.CallActivityAsync <SearchIssue>(nameof(CreatePRReviewDecorator) + "_GetIssues", cIContext); // Get issues that already created var pullRequestState = await context.CallActivityAsync <PullRequestState>("PullRequestStateUtility_GetPullRequestState", new PullRequestStateKey { PartitionKey = _repositoryContext.GetFullNameWithUnderscore(), RowKey = cIContext.PullRequestId }); string entityId = pullRequestState?.EntityId ?? context.NewGuid().ToString(); EntityStateResponse <PullRequestStateContext> response = await context.CallActivityAsync <EntityStateResponse <PullRequestStateContext> >( nameof(CreatePRReviewDecorator) + "_GetPullRequestStateContext", entityId); var pullRequestDetailContext = response.EntityState; pullRequestDetailContext = pullRequestDetailContext ?? new PullRequestStateContext() { PullRequestNumber = int.Parse(cIContext.PullRequestId) }; var unCommentedIssue = issues.issues.Where(issue => !pullRequestDetailContext.CreatedReviewComment.Contains(new CreatedReviewComment() { IssueId = issue.key })).ToList(); foreach (var issue in unCommentedIssue) { var issueContext = (cIContext, issue); var createdPrReviewComment = await context.CallActivityAsync <JObject>(nameof(CreatePRReviewDecorator) + "_CreatePRReviewComment", issueContext); if (createdPrReviewComment != null) { pullRequestDetailContext.Add(new CreatedReviewComment() { IssueId = issue.key, CommentId = (int)createdPrReviewComment["Id"], ProjectKey = cIContext.ProjectKey }); } } await context.CallEntityAsync <PullRequestStateContext>(new EntityId(nameof(PullRequestEntity), entityId), "update", pullRequestDetailContext); pullRequestState = pullRequestState ?? new PullRequestState(); pullRequestState.EntityId = entityId; pullRequestState.PartitionKey = pullRequestState.PartitionKey ?? _repositoryContext.Owner + "_" + _repositoryContext.Name; pullRequestState.RowKey = pullRequestState.RowKey ?? cIContext.PullRequestId; await context.CallActivityAsync("PullRequestStateUtility_CreateOrUpdatePullRequestState", pullRequestState); }
public static async Task WaitingOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext ctx, ILogger log) { var orchestratorArgs = ctx.GetInput <OrchestratorArgs>(); // Using an entity as a cache for the data of the device like // - OfflineAfter, static metadata, typically coming from a device registry (loaded during initialization of entity) // - LastMessageReceived, 'hot' data, not essential for current PoC but could be usefull later on var entity = new EntityId(nameof(DeviceEntity), orchestratorArgs.DeviceId); var offlineAfter = await ctx.CallEntityAsync <TimeSpan>(entity, "GetOfflineAfter"); var lastActivity = await ctx.CallEntityAsync <DateTime?>(entity, "GetLastMessageReceived"); if (!ctx.IsReplaying && (!lastActivity.HasValue || ctx.CurrentUtcDateTime - lastActivity > offlineAfter)) { // This runs for the first message ever for a device id // Also, after a device has gone offline and comes back online, this orchestrator starts again Last Activity should then be longer ago then the offline after log.LogInformation($"Device {orchestratorArgs.DeviceId}, was unkown or offline and is now online!"); await ctx.CallActivityAsync(nameof(SendStatusUpdate), new StatusUpdateArgs(orchestratorArgs.DeviceId, true)); } try { await ctx.WaitForExternalEvent("MessageReceived", offlineAfter); if (!ctx.IsReplaying) { log.LogInformation($"Message received for device {orchestratorArgs.DeviceId}, resetting timeout of {offlineAfter.TotalSeconds} seconds offline detection..."); } ctx.ContinueAsNew(orchestratorArgs); return; } catch (TimeoutException) { if (!ctx.IsReplaying) { log.LogWarning($"Device {orchestratorArgs.DeviceId}, is now offline after waiting for {offlineAfter.TotalSeconds} seconds"); } await ctx.CallActivityAsync(nameof(SendStatusUpdate), new StatusUpdateArgs(orchestratorArgs.DeviceId, false)); return; } }
public static async Task <string> DatabasePutOrchestratorAsync( [OrchestrationTrigger] IDurableOrchestrationContext context) { var operation = context.GetInput <WriteOperation>(); EntityId id = new EntityId(nameof(Register), operation.Key); return(await context.CallEntityAsync <string>(id, "set", operation.Value)); }
public static async Task <int> GetBalance( [OrchestrationTrigger] IDurableOrchestrationContext context) { var accountId = context.GetInput <string>(); EntityId id = new EntityId(nameof(Account), accountId); return(await context.CallEntityAsync <int>(id, "balance")); }
public static async Task <string> Withdraw( [OrchestrationTrigger] IDurableOrchestrationContext context) { var accountOperation = context.GetInput <AccountOperation>(); EntityId id = new EntityId(nameof(Account), accountOperation.AccountId); return(await context.CallEntityAsync <string>(id, "withdraw", accountOperation.Amount)); }
public static async Task <string> DatabaseGetOrchestratorAsync( [OrchestrationTrigger] IDurableOrchestrationContext context) { var key = context.GetInput <string>(); EntityId id = new EntityId(nameof(Register), key); return(await context.CallEntityAsync <string>(id, "get")); }
public static async Task <string> LaunchOrchestrationFromEntity([OrchestrationTrigger] IDurableOrchestrationContext ctx) { var entityId = new EntityId("Launcher", ctx.NewGuid().ToString()); await ctx.CallEntityAsync(entityId, "launch", "hello"); while (true) { var orchestrationId = await ctx.CallEntityAsync <string>(entityId, "get"); if (orchestrationId != null) { return(orchestrationId); } await ctx.CreateTimer(DateTime.UtcNow + TimeSpan.FromSeconds(1), CancellationToken.None); } }
public static async Task RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { VMInfo input = context.GetInput <VMInfo>(); EntityId id = new EntityId("VM", input.VMId); await context.CallEntityAsync(id, input.Action, input.Hour); return; }
public static async Task ProjectCommandSerializationOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context, ILogger log) { if (context is null) { throw new ArgumentNullException(nameof(context)); } var command = context.GetInput <ICommand>(); if (command.ProjectId.HasValue) { var commandEntityId = new EntityId(nameof(ProjectCommandSerializationEntity), command.ProjectId.ToString()); var commandDependencyId = default(string); using (await context.LockAsync(commandEntityId).ConfigureAwait(true)) { // register the new command is a critical section and needs a lock // if there's an dependency it's guid is returned; otherwise null commandDependencyId = await context .CallEntityAsync <string>(commandEntityId, null, command) .ConfigureAwait(true); } if (Guid.TryParse(commandDependencyId, out var correlationId)) { var notification = new ProjectCommandNotification() { InstanceId = context.InstanceId, CorrelationId = correlationId }; var waitForExternalEvent = await context .CallActivityAsync <bool>(nameof(ProjectCommandSerializationActivity), notification) .ConfigureAwait(true); if (waitForExternalEvent) { context .CreateReplaySafeLogger(log) .LogWarning($"{notification.InstanceId} - Waiting for command {notification.CorrelationId}"); await context .WaitForExternalEvent(notification.CorrelationId.ToString()) .ConfigureAwait(true); context .CreateReplaySafeLogger(log) .LogWarning($"{notification.InstanceId} - Resuming"); } } } }
public static async Task <Status> RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext ctx) { var actArgs = ctx.GetInput <ExecuteActionArguments>(); var entityId = new EntityId(typeof(ReportingManagementState).Name, actArgs.StateDetails.Username); await ctx.CallEntityAsync <object>(entityId, "SavePowerBIConnection", actArgs.ActionRequest); return(Status.Success); }
public async Task <bool> IsExecutionPermitted(string breakerId, ILogger log, IDurableOrchestrationContext orchestrationContext) { if (string.IsNullOrEmpty(breakerId)) { throw new ArgumentNullException($"{nameof(breakerId)}"); } log?.LogCircuitBreakerMessage(breakerId, $"Asking IsExecutionPermitted (consistency priority) for circuit-breaker = '{breakerId}'."); return(await orchestrationContext.CallEntityAsync <bool>(DurableCircuitBreakerEntity.GetEntityId(breakerId), DurableCircuitBreakerEntity.Operation.IsExecutionPermitted)); }
public static async Task RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { EntityId id = new EntityId(nameof(Entity), "key"); // Signal an entity context.SignalEntity(id, "MyOperation", "helloSignal"); // Call an entity await context.CallEntityAsync(id, "MyOperation", "helloCall"); }
public static async Task RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext ctx, ILogger log) { var delayTimeSpan = ctx.GetInput <TimeSpan>(); var maxRetries = 10; var count = 0; // The following loop will execute for as long as the garage door remains open // up to max number of retries. while (true) { DateTime timer = ctx.CurrentUtcDateTime.Add(delayTimeSpan); log.LogInformation($"Setting timer to expire at {timer.ToLocalTime()}"); await ctx.CreateTimer(timer, CancellationToken.None); log.LogInformation("Timer fired!"); try { using (await ctx.LockAsync(EntityId)) { log.LogInformation("Entity lock acquired."); var currentState = await ctx.CallEntityAsync <string>(EntityId, "read", null); log.LogInformation($"Current state is {currentState}."); // If the door is closed already, then don't do anything. if (currentState.ToLowerInvariant() == "closed") { log.LogInformation("Looks like the door was already closed. Will skip sending text message."); break; } await ctx.CallActivityAsync("SendTextMessage", null); } } catch (LockingRulesViolationException ex) { log.LogError(ex, "Failed to lock/call the entity."); } catch (Exception ex) { log.LogError(ex, "Unexpected exception occurred."); } if (count >= maxRetries) { log.LogInformation("Reached max retry count, but the garage door is still open. Will stop checking now."); break; } log.LogInformation("Door is still open. Will schedule another timer to check again."); count++; } }
public async Task Orchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { var commandHookContext = context.GetInput <CommandHookContext>(); var response = await context.CallActivityAsync <EntityStateResponse <PullRequestStateContext> >(nameof(PullRequestEntity) + "_GetPullRequestStateContext", commandHookContext.PullRequestUri.GetEntityId()); // Ignore if the Decoration has not finished. if (response.EntityExists) { PullRequestStateContext pullRequestStateContext = response.EntityState; switch (CommandRouter.GetValueOrDefault(commandHookContext.Command)) { case CommandRouter.CreateWorkItemCommand: // GetIssue that match Scan Provider. You can find the ScanProvider from response. await CreateWorkItem(context, pullRequestStateContext, commandHookContext); break; case CommandRouter.IssueTransitionCommand: await TransitIssueAsync(context, pullRequestStateContext, commandHookContext); break; default: // Create Sorry Comment await context.CallActivityAsync(nameof(CommandOrchestrator) + "_" + BotConfiguration.RepositoryProvider + "_CreateSimpleReplyComment", new CreateSimpleReplyCommentContext() { Body = $"Command [{commandHookContext.Command}] hasn't been supported. Ask bot administrator.", InReplyTo = commandHookContext.ReplyToId, PullRequestId = commandHookContext.PullRequestId }); break; } // Update the CurrentPullRequestStatus await context.CallEntityAsync <PullRequestStateContext>( new EntityId(nameof(PullRequestEntity), commandHookContext.PullRequestUri.GetEntityId()), "update", pullRequestStateContext); } else { await context.CallActivityAsync(nameof(CommandOrchestrator) + "_" + BotConfiguration.RepositoryProvider + "_CreateSimpleReplyComment", new CreateSimpleReplyCommentContext() { Body = "Security Decoration seems not finished. Wait until the PullRequest validation CI has done.", InReplyTo = commandHookContext.ReplyToId, PullRequestId = commandHookContext.PullRequestId }); } }
public async Task <List <string> > RunOrchestrator( [OrchestrationTrigger] IDurableOrchestrationContext context) { var outputs = new List <string>(); // Get Parent Info // Ask the entity or StorageAccount if there is duplication // Create a work item var comment = context.GetInput <PRCommentCreated>(); // Get the parent review comment // PullRequestReviewComment can't deserialize. var parentReviewComment = await context.CallActivityAsync <JObject>(nameof(CommandBaseCommand) + "_GetParentReview", comment); // Get the State of the PullRequestState var pullRequestState = await context.CallActivityAsync <PullRequestState>("PullRequestStateUtility_GetPullRequestState", new PullRequestStateKey { PartitionKey = comment.repository.full_name.ToPartitionKey(), RowKey = comment.pull_request.number.ToString() }); // Ask the entity has duplication string entityId = pullRequestState?.EntityId ?? context.NewGuid().ToString(); EntityStateResponse <PullRequestStateContext> response = await context.CallActivityAsync <EntityStateResponse <PullRequestStateContext> >( nameof(CommandBaseCommand) + "_GetPullRequestStateContext", entityId); var pullRequestDetailContext = response.EntityState; // If you don't start CI however, already have a work item comment. (maybe it is rare case) pullRequestDetailContext = pullRequestDetailContext ?? new PullRequestStateContext(); // create a work item pullRequestDetailContext = await ExecuteAsync(context, pullRequestDetailContext, comment, parentReviewComment, new EntityId(nameof(PullRequestEntity), entityId)); // update Entity await context.CallEntityAsync <PullRequestStateContext>( new EntityId(nameof(PullRequestEntity), entityId), "update", pullRequestDetailContext); // update Status. pullRequestState = pullRequestState ?? new PullRequestState(); pullRequestState.EntityId = entityId; pullRequestState.PartitionKey = pullRequestState.PartitionKey ?? comment.repository.full_name.ToPartitionKey(); pullRequestState.RowKey = pullRequestState.RowKey ?? comment.pull_request.number.ToString(); await context.CallActivityAsync("PullRequestStateUtility_CreateOrUpdatePullRequestState", pullRequestState); return(outputs); }