Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions extensions/Worker.Extensions.Tables/release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
- My change description (#PR/#issue)
-->

### Microsoft.Azure.Functions.Worker.Extensions.Tables 1.2.0
### Microsoft.Azure.Functions.Worker.Extensions.Tables <version>

- Add ability to bind table input to TableClient, TableEntity, and IEnumerable<TableEntity> (#1470)
- <entry>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

namespace Microsoft.Azure.Functions.Worker
{
/// <summary>
/// The exception that is thrown when the current function app payload does not support environment reload.
/// </summary>
public sealed class EnvironmentReloadNotSupportedException : NotSupportedException
{
public EnvironmentReloadNotSupportedException() { }

public EnvironmentReloadNotSupportedException(string message) : base(message) { }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

namespace Microsoft.Azure.Functions.Worker
{
/// <summary>
/// The exception that is thrown when there is no function app payload found.
/// </summary>
public sealed class FunctionAppPayloadNotFoundException : Exception
{
public FunctionAppPayloadNotFoundException() { }

public FunctionAppPayloadNotFoundException(string message) : base(message) { }
}
}
63 changes: 59 additions & 4 deletions host/src/FunctionsNetHost/Grpc/IncomingGrpcMessageHandler.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Grpc.Messages;

namespace FunctionsNetHost.Grpc
Expand Down Expand Up @@ -50,14 +51,33 @@ private async Task Process(StreamingMessage msg)
Logger.LogTrace("Specialization request received.");

var envReloadRequest = msg.FunctionEnvironmentReloadRequest;
foreach (var kv in envReloadRequest.EnvironmentVariables)

var workerConfig = await WorkerConfigUtils.GetWorkerConfig(envReloadRequest.FunctionAppDirectory);

if (workerConfig?.Description is null)
{
EnvironmentUtils.SetValue(kv.Key, kv.Value);
Logger.LogTrace($"Could not find a worker config in {envReloadRequest.FunctionAppDirectory}");
responseMessage.FunctionEnvironmentReloadResponse = BuildFailedEnvironmentReloadResponse();
break;
}

// function app payload which uses an older version of Microsoft.Azure.Functions.Worker package does not support specialization.
if (!workerConfig.Description.CanUsePlaceholder)
{
Logger.LogTrace("App payload uses an older version of Microsoft.Azure.Functions.Worker SDK which does not support placeholder.");
var e = new EnvironmentReloadNotSupportedException("This app is not using the latest version of Microsoft.Azure.Functions.Worker SDK and therefore does not leverage all performance optimizations. See https://aka.ms/azure-functions/dotnet/placeholders for more information.");
responseMessage.FunctionEnvironmentReloadResponse = BuildFailedEnvironmentReloadResponse(e);
break;
}

var applicationExePath = PathUtils.GetApplicationExePath(envReloadRequest.FunctionAppDirectory);
var applicationExePath = Path.Combine(envReloadRequest.FunctionAppDirectory, workerConfig.Description.DefaultWorkerPath!);
Logger.LogTrace($"application path {applicationExePath}");

foreach (var kv in envReloadRequest.EnvironmentVariables)
{
EnvironmentUtils.SetValue(kv.Key, kv.Value);
}

#pragma warning disable CS4014
Task.Run(() =>
#pragma warning restore CS4014
Expand All @@ -74,9 +94,43 @@ private async Task Process(StreamingMessage msg)
break;
}

await MessageChannel.Instance.SendOutboundAsync(responseMessage);
if (responseMessage.ContentCase != StreamingMessage.ContentOneofCase.None)
{
await MessageChannel.Instance.SendOutboundAsync(responseMessage);
}
}

private static FunctionEnvironmentReloadResponse BuildFailedEnvironmentReloadResponse(Exception? exception = null)
{
var response = new FunctionEnvironmentReloadResponse
{
Result = new StatusResult
{
Status = StatusResult.Types.Status.Failure
}
};

response.Result.Exception = ToUserRpcException(exception);

return response;
}

internal static RpcException? ToUserRpcException(Exception? exception)
{
if (exception is null)
{
return null;
}

return new RpcException
{
Message = exception.Message,
Source = exception.Source ?? string.Empty,
StackTrace = exception.StackTrace ?? string.Empty,
Type = exception.GetType().FullName ?? string.Empty,
IsUserException = true
};
}
private static FunctionMetadataResponse BuildFunctionMetadataResponse()
{
var metadataResponse = new FunctionMetadataResponse
Expand All @@ -94,6 +148,7 @@ private static WorkerInitResponse BuildWorkerInitResponse()
{
Result = new StatusResult { Status = StatusResult.Types.Status.Success }
};
response.Capabilities[WorkerCapabilities.EnableUserCodeException] = bool.TrueString;

return response;
}
Expand Down
53 changes: 0 additions & 53 deletions host/src/FunctionsNetHost/Grpc/PathUtils.cs

This file was deleted.

10 changes: 10 additions & 0 deletions host/src/FunctionsNetHost/Grpc/WorkerCapabilities.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

namespace FunctionsNetHost.Grpc
{
internal static class WorkerCapabilities
{
internal const string EnableUserCodeException = "EnableUserCodeException";
}
}
13 changes: 13 additions & 0 deletions host/src/FunctionsNetHost/Grpc/WorkerConfig/WorkerConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

namespace FunctionsNetHost.Grpc
{
/// <summary>
/// Represents a worker configuration instance.
/// </summary>
public sealed class WorkerConfig
{
public WorkerDescription? Description { set; get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System.Text.Json.Serialization;

namespace FunctionsNetHost.Grpc
{
[JsonSerializable(typeof(WorkerConfig))]
[JsonSourceGenerationOptions(IncludeFields = true, PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)]
internal partial class WorkerConfigSerializerContext : JsonSerializerContext { }
}
39 changes: 39 additions & 0 deletions host/src/FunctionsNetHost/Grpc/WorkerConfig/WorkerConfigUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System.Text.Json;

namespace FunctionsNetHost.Grpc
{
internal static class WorkerConfigUtils
{
/// <summary>
/// Builds and returns an instance of <see cref="WorkerConfig"/> from the worker.config.json file if present in the application directory.
/// </summary>
/// <param name="applicationDirectory">The directory where function app deployed payload is present.</param>
internal static async Task<WorkerConfig?> GetWorkerConfig(string applicationDirectory)
{
string workerConfigPath = string.Empty;

try
{
workerConfigPath = Path.Combine(applicationDirectory, "worker.config.json");

using Stream stream = File.OpenRead(workerConfigPath);
var workerConfig = await JsonSerializer.DeserializeAsync(stream, WorkerConfigSerializerContext.Default.WorkerConfig);

return workerConfig;
}
catch (FileNotFoundException)
{
Logger.Log($"worker.config.json not found at {workerConfigPath}. This may indicate missing app payload.");
return null;
}
catch (Exception ex)
{
Logger.Log($"Error in WorkerConfigUtils.GetWorkerConfig.{ex}");
return null;
}
}
}
}
12 changes: 12 additions & 0 deletions host/src/FunctionsNetHost/Grpc/WorkerConfig/WorkerDescription.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

namespace FunctionsNetHost.Grpc
{
public sealed class WorkerDescription
{
public string? DefaultWorkerPath { set; get; }

public bool CanUsePlaceholder { set; get; }
}
}
2 changes: 1 addition & 1 deletion host/src/FunctionsNetHost/global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "8.0.100-rc.1.23455.8",
"version": "8.0.100-rc.2.23502.2",
"allowPrerelease": true,
"rollForward": "latestMinor"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<id>Microsoft.Azure.Functions.DotNetIsolatedNativeHost</id>
<title>Microsoft Azure Functions dotnet-isolated native host</title>
<tags>dotnet-isolated azure-functions azure</tags>
<version>1.0.0</version>
<version>1.0.2</version>
<authors>Microsoft</authors>
<owners>Microsoft</owners>
<projectUrl>https://github.com/Azure/azure-functions-dotnet-worker</projectUrl>
Expand Down
Loading