public async Task <WorkerStatus> GetWorkerStatusAsync() { var workerStatus = new WorkerStatus(); if (!string.IsNullOrEmpty(_workerCapabilities.GetCapabilityState(RpcWorkerConstants.WorkerStatus))) { // get the worker's current status // this will include the OOP worker's channel latency in the request, which can be used upstream // to make scale decisions var message = new StreamingMessage { RequestId = Guid.NewGuid().ToString(), WorkerStatusRequest = new WorkerStatusRequest() }; var sw = ValueStopwatch.StartNew(); var tcs = new TaskCompletionSource <bool>(); if (_workerStatusRequests.TryAdd(message.RequestId, tcs)) { SendStreamingMessage(message); await tcs.Task; var elapsed = sw.GetElapsedTime(); workerStatus.Latency = elapsed; _workerChannelLogger.LogDebug($"[HostMonitor] Worker status request took {elapsed.TotalMilliseconds}ms"); } } workerStatus.IsReady = IsChannelReadyForInvocations(); if (_environment.IsWorkerDynamicConcurrencyEnabled()) { workerStatus.LatencyHistory = GetLatencies(); } return(workerStatus); }
public async Task <WorkerStatus> GetWorkerStatusAsync() { var workerStatus = new WorkerStatus(); if (!string.IsNullOrEmpty(_workerCapabilities.GetCapabilityState(RpcWorkerConstants.WorkerStatus))) { // get the worker's current status // this will include the OOP worker's channel latency in the request, which can be used upstream // to make scale decisions var message = new StreamingMessage { RequestId = Guid.NewGuid().ToString(), WorkerStatusRequest = new WorkerStatusRequest() }; var sw = Stopwatch.StartNew(); var tcs = new TaskCompletionSource <bool>(); if (_workerStatusRequests.TryAdd(message.RequestId, tcs)) { SendStreamingMessage(message); await tcs.Task; sw.Stop(); workerStatus.Latency = sw.Elapsed; _workerChannelLogger.LogDebug($"[HostMonitor] Worker status request took {sw.ElapsedMilliseconds}ms"); } } // get the process stats for the worker var workerProcessStats = _rpcWorkerProcess.GetStats(); workerStatus.ProcessStats = workerProcessStats; if (workerProcessStats.CpuLoadHistory.Any()) { string formattedLoadHistory = string.Join(",", workerProcessStats.CpuLoadHistory); int executingFunctionCount = FunctionInputBuffers.Sum(p => p.Value.Count); _workerChannelLogger.LogDebug($"[HostMonitor] Worker process stats: EffectiveCores={_environment.GetEffectiveCoresCount()}, ProcessId={_rpcWorkerProcess.Id}, ExecutingFunctions={executingFunctionCount}, CpuLoadHistory=({formattedLoadHistory}), AvgLoad={workerProcessStats.CpuLoadHistory.Average()}, MaxLoad={workerProcessStats.CpuLoadHistory.Max()}"); } return(workerStatus); }
public static async Task <InvocationRequest> ToRpcInvocationRequest(this ScriptInvocationContext context, ILogger logger, GrpcCapabilities capabilities) { bool excludeHttpTriggerMetadata = !string.IsNullOrEmpty(capabilities.GetCapabilityState(RpcWorkerConstants.RpcHttpTriggerMetadataRemoved)); var invocationRequest = new InvocationRequest { FunctionId = context.FunctionMetadata.GetFunctionId(), InvocationId = context.ExecutionContext.InvocationId.ToString(), TraceContext = GetRpcTraceContext(context.Traceparent, context.Tracestate, context.Attributes, logger), }; var rpcValueCache = new Dictionary <object, TypedData>(); foreach (var input in context.Inputs) { TypedData rpcValue = null; if (input.val == null || !rpcValueCache.TryGetValue(input.val, out rpcValue)) { rpcValue = await input.val.ToRpc(logger, capabilities); if (input.val != null) { rpcValueCache.Add(input.val, rpcValue); } } var parameterBinding = new ParameterBinding { Name = input.name, Data = rpcValue }; invocationRequest.InputData.Add(parameterBinding); } foreach (var pair in context.BindingData) { if (ShouldSkipBindingData(pair, context, excludeHttpTriggerMetadata)) { continue; } if (!rpcValueCache.TryGetValue(pair.Value, out TypedData rpcValue)) { rpcValue = await pair.Value.ToRpc(logger, capabilities); rpcValueCache.Add(pair.Value, rpcValue); } invocationRequest.TriggerMetadata.Add(pair.Key, rpcValue); } return(invocationRequest); }
private static bool ShouldUseNullableValueDictionary(GrpcCapabilities capabilities) { return(!string.IsNullOrEmpty(capabilities.GetCapabilityState(RpcWorkerConstants.UseNullableValueDictionaryForHttp))); }
private static bool ShouldIgnoreEmptyHeaderValues(GrpcCapabilities capabilities) { return(!string.IsNullOrEmpty(capabilities.GetCapabilityState(RpcWorkerConstants.IgnoreEmptyValuedRpcHttpHeaders))); }
private static bool IsTypedDataCollectionSupported(GrpcCapabilities capabilities) { return(!string.IsNullOrEmpty(capabilities.GetCapabilityState(RpcWorkerConstants.TypedDataCollection))); }
private static bool IsBodyOnlySupported(GrpcCapabilities capabilities) { return(!string.IsNullOrEmpty(capabilities.GetCapabilityState(RpcWorkerConstants.RpcHttpBodyOnly))); }
private static bool IsRawBodyBytesRequested(GrpcCapabilities capabilities) { return(!string.IsNullOrEmpty(capabilities.GetCapabilityState(RpcWorkerConstants.RawHttpBodyBytes))); }
public static async Task <InvocationRequest> ToRpcInvocationRequest(this ScriptInvocationContext context, ILogger logger, GrpcCapabilities capabilities, bool isSharedMemoryDataTransferEnabled, ISharedMemoryManager sharedMemoryManager) { bool excludeHttpTriggerMetadata = !string.IsNullOrEmpty(capabilities.GetCapabilityState(RpcWorkerConstants.RpcHttpTriggerMetadataRemoved)); var invocationRequest = new InvocationRequest { FunctionId = context.FunctionMetadata.GetFunctionId(), InvocationId = context.ExecutionContext.InvocationId.ToString(), TraceContext = GetRpcTraceContext(context.Traceparent, context.Tracestate, context.Attributes, logger), }; SetRetryContext(context, invocationRequest); var rpcValueCache = new Dictionary <object, TypedData>(); Dictionary <object, RpcSharedMemory> sharedMemValueCache = null; StringBuilder logBuilder = null; bool usedSharedMemory = false; if (isSharedMemoryDataTransferEnabled) { sharedMemValueCache = new Dictionary <object, RpcSharedMemory>(); logBuilder = new StringBuilder(); } foreach (var input in context.Inputs) { RpcSharedMemory sharedMemValue = null; ParameterBinding parameterBinding = null; if (isSharedMemoryDataTransferEnabled) { // Try to transfer this data over shared memory instead of RPC if (input.val == null || !sharedMemValueCache.TryGetValue(input.val, out sharedMemValue)) { sharedMemValue = await input.val.ToRpcSharedMemoryAsync(logger, invocationRequest.InvocationId, sharedMemoryManager); if (input.val != null) { sharedMemValueCache.Add(input.val, sharedMemValue); } } } if (sharedMemValue != null) { // Data was successfully transferred over shared memory; create a ParameterBinding accordingly parameterBinding = new ParameterBinding { Name = input.name, RpcSharedMemory = sharedMemValue }; usedSharedMemory = true; logBuilder.AppendFormat("{0}:{1},", input.name, sharedMemValue.Count); } else { // Data was not transferred over shared memory (either disabled, type not supported or some error); resort to RPC TypedData rpcValue = null; if (input.val == null || !rpcValueCache.TryGetValue(input.val, out rpcValue)) { rpcValue = await input.val.ToRpc(logger, capabilities); if (input.val != null) { rpcValueCache.Add(input.val, rpcValue); } } parameterBinding = new ParameterBinding { Name = input.name, Data = rpcValue }; } invocationRequest.InputData.Add(parameterBinding); } foreach (var pair in context.BindingData) { if (ShouldSkipBindingData(pair, context, excludeHttpTriggerMetadata)) { continue; } if (!rpcValueCache.TryGetValue(pair.Value, out TypedData rpcValue)) { rpcValue = await pair.Value.ToRpc(logger, capabilities); rpcValueCache.Add(pair.Value, rpcValue); } invocationRequest.TriggerMetadata.Add(pair.Key, rpcValue); } if (usedSharedMemory) { logger.LogDebug("Shared memory usage for request of invocation Id: {Id} is {SharedMemoryUsage}", invocationRequest.InvocationId, logBuilder.ToString()); } return(invocationRequest); }