/// <summary> /// Handles workflow queries. /// </summary> /// <param name="request">The request message.</param> /// <returns>The reply message.</returns> internal async Task <WorkflowQueryInvokeReply> OnQueryAsync(WorkflowQueryInvokeRequest request) { await SyncContext.Clear; Covenant.Requires <ArgumentNullException>(request != null, nameof(request)); try { WorkflowBase.CallContext.Value = WorkflowCallContext.Query; var workflow = GetWorkflow(request.ContextId); if (workflow != null) { Workflow.Current = workflow.Workflow; // Initialize the ambient workflow information for workflow library code. // Handle built-in queries. switch (request.QueryName) { case TemporalClient.QueryStack: var trace = string.Empty; if (workflow.StackTrace != null) { trace = workflow.StackTrace.ToString(); } return(new WorkflowQueryInvokeReply() { RequestId = request.RequestId, Result = Client.DataConverter.ToData(trace) }); case TemporalClient.QuerySyncSignal: // The arguments for this signal is the (string) ID of the target // signal being polled for status. var syncSignalArgs = TemporalHelper.BytesToArgs(JsonDataConverter.Instance, request.QueryArgs, new Type[] { typeof(string) }); var syncSignalId = (string)(syncSignalArgs.Length > 0 ? syncSignalArgs[0] : null); var syncSignalStatus = workflow.GetSignalStatus(syncSignalId); Covenant.Assert(false); // This should never happen if (syncSignalStatus.Completed) { // Indicate that the completed signal has reported the status // to the calling client as well as returned the result, if any. syncSignalStatus.Acknowledged = true; syncSignalStatus.AcknowledgeTime = DateTime.UtcNow; } return(new WorkflowQueryInvokeReply() { RequestId = request.RequestId, Result = Client.DataConverter.ToData(syncSignalStatus) }); } // Handle user queries. var method = workflow.Workflow.MethodMap.GetQueryMethod(request.QueryName); if (method != null) { var resultType = method.ReturnType; var methodParameterTypes = method.GetParameterTypes(); var serializedResult = Array.Empty <byte>(); if (resultType.IsGenericType) { // Query method returns: Task<T> var result = await NeonHelper.GetTaskResultAsObjectAsync((Task)method.Invoke(workflow, TemporalHelper.BytesToArgs(Client.DataConverter, request.QueryArgs, methodParameterTypes))); serializedResult = Client.DataConverter.ToData(result); } else { // Query method returns: Task await(Task) method.Invoke(workflow, TemporalHelper.BytesToArgs(Client.DataConverter, request.QueryArgs, methodParameterTypes)); } return(new WorkflowQueryInvokeReply() { RequestId = request.RequestId, Result = serializedResult }); } else { return(new WorkflowQueryInvokeReply() { Error = new EntityNotExistsException($"Workflow type [{workflow.GetType().FullName}] does not define a query handler for [queryType={request.QueryName}].").ToTemporalError() }); } } else { return(new WorkflowQueryInvokeReply() { Error = new EntityNotExistsException($"Workflow with [contextID={request.ContextId}] does not exist.").ToTemporalError() }); } } catch (Exception e) { log.LogError(e); return(new WorkflowQueryInvokeReply() { Error = new TemporalError(e) }); } finally { WorkflowBase.CallContext.Value = WorkflowCallContext.None; } }
/// <summary> /// Handles workflow queries. /// </summary> /// <param name="client">The Cadence client.</param> /// <param name="request">The request message.</param> /// <returns>The reply message.</returns> internal static async Task <WorkflowQueryInvokeReply> OnQueryAsync(CadenceClient client, WorkflowQueryInvokeRequest request) { Covenant.Requires <ArgumentNullException>(client != null); Covenant.Requires <ArgumentNullException>(request != null); try { var workflow = GetWorkflow(client, request.ContextId); if (workflow != null) { var method = workflow.Workflow.MethodMap.GetQueryMethod(request.QueryName); if (method != null) { var result = await(Task <byte[]>)(method.Invoke(workflow, new object[] { request.QueryArgs })); return(new WorkflowQueryInvokeReply() { RequestId = request.RequestId, Result = result }); } else { return(new WorkflowQueryInvokeReply() { Error = new CadenceEntityNotExistsException($"Workflow type [{workflow.GetType().FullName}] does not define a query handler for [queryType={request.QueryName}].").ToCadenceError() }); } } else { return(new WorkflowQueryInvokeReply() { Error = new CadenceEntityNotExistsException($"Workflow with [contextID={request.ContextId}] does not exist.").ToCadenceError() }); } } catch (Exception e) { return(new WorkflowQueryInvokeReply() { Error = new CadenceError(e) }); } }
/// <summary> /// Handles workflow queries. /// </summary> /// <param name="client">The Cadence client.</param> /// <param name="request">The request message.</param> /// <returns>The reply message.</returns> internal static async Task<WorkflowQueryInvokeReply> OnQueryAsync(CadenceClient client, WorkflowQueryInvokeRequest request) { Covenant.Requires<ArgumentNullException>(client != null, nameof(client)); Covenant.Requires<ArgumentNullException>(request != null, nameof(request)); try { WorkflowBase.CallContext.Value = WorkflowCallContext.Query; var workflow = GetWorkflow(client, request.ContextId); if (workflow != null) { // Handle built-in queries. if (request.QueryName == "__stack_trace") { var trace = string.Empty; if (workflow.StackTrace != null) { trace = workflow.StackTrace.ToString(); } return new WorkflowQueryInvokeReply() { RequestId = request.RequestId, Result = NeonHelper.JsonSerializeToBytes(trace) }; } // Handle user queries. var method = workflow.Workflow.MethodMap.GetQueryMethod(request.QueryName); if (method != null) { var resultType = method.ReturnType; var methodParameterTypes = method.GetParameterTypes(); var serializedResult = emptyBytes; if (resultType.IsGenericType) { // Query method returns: Task<T> var result = await NeonHelper.GetTaskResultAsObjectAsync((Task)method.Invoke(workflow, client.DataConverter.FromDataArray(request.QueryArgs, methodParameterTypes))); serializedResult = client.DataConverter.ToData(result); } else { // Query method returns: Task await (Task)method.Invoke(workflow, client.DataConverter.FromDataArray(request.QueryArgs, methodParameterTypes)); } return new WorkflowQueryInvokeReply() { RequestId = request.RequestId, Result = serializedResult }; } else { return new WorkflowQueryInvokeReply() { Error = new EntityNotExistsException($"Workflow type [{workflow.GetType().FullName}] does not define a query handler for [queryType={request.QueryName}].").ToCadenceError() }; } } else { return new WorkflowQueryInvokeReply() { Error = new EntityNotExistsException($"Workflow with [contextID={request.ContextId}] does not exist.").ToCadenceError() }; } } catch (Exception e) { log.LogError(e); return new WorkflowQueryInvokeReply() { Error = new CadenceError(e) }; } finally { WorkflowBase.CallContext.Value = WorkflowCallContext.None; } }