Skip to content

Commit d25972b

Browse files
authored
Refactor RpcInitializationService and add unit tests (#3861)
1 parent 610011d commit d25972b

File tree

11 files changed

+203
-44
lines changed

11 files changed

+203
-44
lines changed

src/WebJobs.Script/Description/Rpc/ScriptInvocationResult.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace Microsoft.Azure.WebJobs.Script.Description
77
{
8-
public class ScriptInvocationResult
8+
internal class ScriptInvocationResult
99
{
1010
public object Return { get; set; }
1111

src/WebJobs.Script/Rpc/FunctionRegistration/FunctionDispatcher.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
namespace Microsoft.Azure.WebJobs.Script.Rpc
1818
{
19-
public class FunctionDispatcher : IFunctionDispatcher
19+
internal class FunctionDispatcher : IFunctionDispatcher
2020
{
2121
private IScriptEventManager _eventManager;
2222
private IMetricsLogger _metricsLogger;

src/WebJobs.Script/Rpc/ILanguageWorkerChannelManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace Microsoft.Azure.WebJobs.Script.Rpc
1010
{
1111
public interface ILanguageWorkerChannelManager
1212
{
13-
Task InitializeAsync();
13+
Task InitializeChannelAsync(string language);
1414

1515
ILanguageWorkerChannel GetChannel(string language);
1616

src/WebJobs.Script/Rpc/LanguageWorkerChannel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
namespace Microsoft.Azure.WebJobs.Script.Rpc
2626
{
27-
public class LanguageWorkerChannel : ILanguageWorkerChannel
27+
internal class LanguageWorkerChannel : ILanguageWorkerChannel
2828
{
2929
private readonly TimeSpan processStartTimeout = TimeSpan.FromSeconds(40);
3030
private readonly TimeSpan workerInitTimeout = TimeSpan.FromSeconds(30);

src/WebJobs.Script/Rpc/LanguageWorkerChannelManager.cs

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@ namespace Microsoft.Azure.WebJobs.Script.Rpc
1616
{
1717
public class LanguageWorkerChannelManager : ILanguageWorkerChannelManager
1818
{
19-
private readonly IEnumerable<string> _languages = new List<string>()
20-
{
21-
LanguageWorkerConstants.JavaLanguageWorkerName
22-
};
23-
2419
private readonly IEnumerable<WorkerConfig> _workerConfigs = null;
2520
private readonly ILogger _logger = null;
2621
private readonly TimeSpan processStartTimeout = TimeSpan.FromSeconds(40);
@@ -83,40 +78,18 @@ public ILanguageWorkerChannel CreateLanguageWorkerChannel(string workerId, strin
8378
attemptCount);
8479
}
8580

86-
public Task InitializeAsync()
87-
{
88-
_workerRuntime = _environment.GetEnvironmentVariable(LanguageWorkerConstants.FunctionWorkerRuntimeSettingName);
89-
if (SystemEnvironment.Instance.IsLinuxAppServiceEnvironment())
90-
{
91-
return Task.CompletedTask;
92-
}
93-
if (SystemEnvironment.Instance.IsLinuxContainerEnvironment())
94-
{
95-
return Task.CompletedTask;
96-
}
97-
if (string.IsNullOrEmpty(_workerRuntime))
98-
{
99-
return Task.WhenAll(_languages.Select(language => InitializeChannelAsync(language)));
100-
}
101-
if (_languages.Contains(_workerRuntime))
102-
{
103-
return InitializeChannelAsync(_workerRuntime);
104-
}
105-
return Task.CompletedTask;
106-
}
107-
108-
internal async Task InitializeChannelAsync(string language)
81+
public async Task InitializeChannelAsync(string runtime)
10982
{
110-
_logger?.LogDebug("Initializing language worker channel for {runtime}:", language);
111-
await InitializeLanguageWorkerChannel(language, _applicationHostOptions.CurrentValue.ScriptPath);
83+
_logger?.LogDebug("Initializing language worker channel for runtime:{runtime}", runtime);
84+
await InitializeLanguageWorkerChannel(runtime, _applicationHostOptions.CurrentValue.ScriptPath);
11285
}
11386

11487
private async Task InitializeLanguageWorkerChannel(string language, string scriptRootPath)
11588
{
11689
try
11790
{
11891
string workerId = Guid.NewGuid().ToString();
119-
_logger.LogInformation($"Creating language worker channel for runtime", language);
92+
_logger.LogInformation("Creating language worker channel for runtime:{runtime}", language);
12093
ILanguageWorkerChannel languageWorkerChannel = CreateLanguageWorkerChannel(workerId, scriptRootPath, language, null, null, 0);
12194
languageWorkerChannel.StartWorkerProcess();
12295
IObservable<RpcChannelReadyEvent> rpcChannelReadyEvent = _eventManager.OfType<RpcChannelReadyEvent>()

src/WebJobs.Script/Rpc/LanguageWorkerChannelUtilities.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
namespace Microsoft.Azure.WebJobs.Script.Rpc
1111
{
12-
public static class LanguageWorkerChannelUtilities
12+
internal static class LanguageWorkerChannelUtilities
1313
{
1414
private static int maxNumberOfErrorMessages = 3;
1515

src/WebJobs.Script/Rpc/ProcessManagement/IWorkerProcessFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace Microsoft.Azure.WebJobs.Script.Rpc
77
{
8-
public interface IWorkerProcessFactory
8+
internal interface IWorkerProcessFactory
99
{
1010
// TODO: create an abstraction like Executable in the cli which wraps the process
1111
Process CreateWorkerProcess(WorkerContext context);

src/WebJobs.Script/Rpc/ProcessManagement/WorkerContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
namespace Microsoft.Azure.WebJobs.Script.Rpc
88
{
99
// Arguments to start a worker process
10-
public class WorkerContext
10+
internal class WorkerContext
1111
{
1212
public Uri ServerUri { get; set; }
1313

src/WebJobs.Script/Rpc/RpcInitializationService.cs

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,22 @@ namespace Microsoft.Azure.WebJobs.Script.Rpc
1616
public class RpcInitializationService : IHostedService
1717
{
1818
private readonly IOptionsMonitor<ScriptApplicationHostOptions> _applicationHostOptions;
19-
19+
private readonly IEnvironment _environment;
2020
private readonly ILanguageWorkerChannelManager _languageWorkerChannelManager;
2121
private readonly IRpcServer _rpcServer;
2222
private readonly ILogger _logger;
2323

24-
public RpcInitializationService(IOptionsMonitor<ScriptApplicationHostOptions> applicationHostOptions, IRpcServer rpcServer, ILanguageWorkerChannelManager languageWorkerChannelManager, ILoggerFactory loggerFactory)
24+
private List<string> _languages = new List<string>()
25+
{
26+
LanguageWorkerConstants.JavaLanguageWorkerName
27+
};
28+
29+
public RpcInitializationService(IOptionsMonitor<ScriptApplicationHostOptions> applicationHostOptions, IEnvironment environment, IRpcServer rpcServer, ILanguageWorkerChannelManager languageWorkerChannelManager, ILoggerFactory loggerFactory)
2530
{
2631
_applicationHostOptions = applicationHostOptions ?? throw new ArgumentNullException(nameof(applicationHostOptions));
2732
_logger = loggerFactory.CreateLogger(ScriptConstants.LogCategoryRpcInitializationService);
2833
_rpcServer = rpcServer;
34+
_environment = environment;
2935
_languageWorkerChannelManager = languageWorkerChannelManager ?? throw new ArgumentNullException(nameof(languageWorkerChannelManager));
3036
}
3137

@@ -35,19 +41,19 @@ public async Task StartAsync(CancellationToken cancellationToken)
3541
{
3642
return;
3743
}
38-
_logger.LogInformation("Initializing Rpc Channels Manager");
44+
_logger.LogInformation("Starting Rpc Initialization Service.");
3945
await InitializeRpcServerAsync();
40-
await _languageWorkerChannelManager.InitializeAsync();
46+
await InitializeChannelsAsync();
4147
}
4248

4349
public async Task StopAsync(CancellationToken cancellationToken)
4450
{
4551
_logger.LogInformation("Shuttingdown Rpc Channels Manager");
46-
await _rpcServer.KillAsync();
4752
await _languageWorkerChannelManager.ShutdownChannelsAsync();
53+
await _rpcServer.KillAsync();
4854
}
4955

50-
private async Task InitializeRpcServerAsync()
56+
internal async Task InitializeRpcServerAsync()
5157
{
5258
try
5359
{
@@ -59,5 +65,31 @@ private async Task InitializeRpcServerAsync()
5965
var hostInitEx = new HostInitializationException($"Failed to start Rpc Server. Check if your app is hitting connection limits.", grpcInitEx);
6066
}
6167
}
68+
69+
internal Task InitializeChannelsAsync()
70+
{
71+
string workerRuntime = _environment.GetEnvironmentVariable(LanguageWorkerConstants.FunctionWorkerRuntimeSettingName);
72+
if (_environment.IsLinuxAppServiceEnvironment())
73+
{
74+
return Task.CompletedTask;
75+
}
76+
if (_environment.IsLinuxContainerEnvironment())
77+
{
78+
return Task.CompletedTask;
79+
}
80+
if (string.IsNullOrEmpty(workerRuntime) && _environment.IsPlaceholderModeEnabled())
81+
{
82+
// Only warm up language workers in placeholder mode in worker runtime is not set
83+
return Task.WhenAll(_languages.Select(runtime => _languageWorkerChannelManager.InitializeChannelAsync(runtime)));
84+
}
85+
if (_languages.Contains(workerRuntime))
86+
{
87+
return _languageWorkerChannelManager.InitializeChannelAsync(workerRuntime);
88+
}
89+
return Task.CompletedTask;
90+
}
91+
92+
// To help with unit tests
93+
internal void AddSupportedRuntime(string language) => _languages.Add(language);
6294
}
6395
}

test/WebJobs.Script.Tests.Shared/TestHelpers.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using System.Threading.Tasks;
1414
using Microsoft.Azure.WebJobs.Script.Abstractions;
1515
using Microsoft.Azure.WebJobs.Script.Rpc;
16+
using Microsoft.Azure.WebJobs.Script.WebHost;
1617
using Microsoft.Extensions.Configuration;
1718
using Microsoft.Extensions.Options;
1819
using Microsoft.WindowsAzure.Storage.Blob;
@@ -260,6 +261,15 @@ public static IList<WorkerConfig> GetTestWorkerConfigs()
260261
};
261262
}
262263

264+
public static string CreateOfflineFile(string rootPath)
265+
{
266+
// create a test offline file
267+
var offlineFilePath = Path.Combine(Path.GetTempPath(), ScriptConstants.AppOfflineFileName);
268+
string content = FileUtility.ReadResourceString($"{ScriptConstants.ResourcePath}.{ScriptConstants.AppOfflineFileName}", typeof(HttpException).Assembly);
269+
File.WriteAllText(offlineFilePath, content);
270+
return offlineFilePath;
271+
}
272+
263273
public static WorkerDescription GetTestWorkerDescription(string language, string extension)
264274
{
265275
return new WorkerDescription()

0 commit comments

Comments
 (0)