Skip to content

Commit 2ea7952

Browse files
authored
handling null refs in channel disposal (#9339)
1 parent 348d91f commit 2ea7952

File tree

3 files changed

+56
-11
lines changed

3 files changed

+56
-11
lines changed

src/WebJobs.Script.Grpc/Channel/GrpcWorkerChannel.cs

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,16 +1261,44 @@ protected virtual void Dispose(bool disposing)
12611261
_timer?.Dispose();
12621262

12631263
// unlink function inputs
1264-
foreach (var link in _inputLinks)
1264+
if (_inputLinks is not null)
12651265
{
1266-
link.Dispose();
1266+
foreach (var link in _inputLinks)
1267+
{
1268+
if (link is null)
1269+
{
1270+
// This log is temporarily added for diagnostic purposes.
1271+
_workerChannelLogger.LogDebug("An input link is null. Skipping disposal.");
1272+
}
1273+
1274+
link?.Dispose();
1275+
}
1276+
}
1277+
else
1278+
{
1279+
// This log is temporarily added for diagnostic purposes.
1280+
_workerChannelLogger.LogDebug("The input links collection is null. Skipping disposal of any individual input links.");
12671281
}
12681282

12691283
(_rpcWorkerProcess as IDisposable)?.Dispose();
12701284

1271-
foreach (var sub in _eventSubscriptions)
1285+
if (_eventSubscriptions is not null)
1286+
{
1287+
foreach (var sub in _eventSubscriptions)
1288+
{
1289+
if (sub is null)
1290+
{
1291+
// This log is temporarily added for diagnostic purposes.
1292+
_workerChannelLogger.LogDebug("An event subscription is null. Skipping disposal.");
1293+
}
1294+
1295+
sub?.Dispose();
1296+
}
1297+
}
1298+
else
12721299
{
1273-
sub.Dispose();
1300+
// This log is temporarily added for diagnostic purposes.
1301+
_workerChannelLogger.LogDebug("The event subscriptions collection is null. Skipping disposal of any individual subscriptions.");
12741302
}
12751303

12761304
// shut down the channels

src/WebJobs.Script/Workers/Rpc/FunctionRegistration/RpcFunctionInvocationDispatcher.cs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -507,16 +507,29 @@ private async Task DisposeAndRestartWorkerChannel(string runtime, string workerI
507507
}
508508

509509
_logger.LogDebug("Attempting to dispose webhost or jobhost channel for workerId: '{channelId}', runtime: '{language}'", workerId, runtime);
510-
bool isWebHostChannelDisposed = await _webHostLanguageWorkerChannelManager.ShutdownChannelIfExistsAsync(runtime, workerId, workerException);
510+
511+
bool isWebHostChannelDisposed = false;
511512
bool isJobHostChannelDisposed = false;
512-
if (!isWebHostChannelDisposed)
513+
514+
try
513515
{
514-
isJobHostChannelDisposed = await _jobHostLanguageWorkerChannelManager.ShutdownChannelIfExistsAsync(workerId, workerException);
515-
}
516+
isWebHostChannelDisposed = await _webHostLanguageWorkerChannelManager.ShutdownChannelIfExistsAsync(runtime, workerId, workerException);
517+
if (!isWebHostChannelDisposed)
518+
{
519+
isJobHostChannelDisposed = await _jobHostLanguageWorkerChannelManager.ShutdownChannelIfExistsAsync(workerId, workerException);
520+
}
516521

517-
if (!isWebHostChannelDisposed && !isJobHostChannelDisposed)
522+
if (!isWebHostChannelDisposed && !isJobHostChannelDisposed)
523+
{
524+
_logger.LogDebug("Did not find WebHost or JobHost channel to dispose for workerId: '{channelId}', runtime: '{language}'", workerId, runtime);
525+
}
526+
}
527+
catch (Exception ex)
518528
{
519-
_logger.LogDebug("Did not find WebHost or JobHost channel to dispose for workerId: '{channelId}', runtime: '{language}'", workerId, runtime);
529+
// If an exception was thrown while trying to shut down a channel, we're left in an undetermined state. The safest thing to do is
530+
// to restart the entire host and let everything come back up from scratch.
531+
_logger.LogError(ex, "Error while shutting down channel for workerId '{channelId}'. Shutting down and proactively recycling the Functions Host to recover.", workerId);
532+
_applicationLifetime.StopApplication();
520533
}
521534

522535
if (ShouldRestartWorkerChannel(runtime, isWebHostChannelDisposed, isJobHostChannelDisposed))

src/WebJobs.Script/Workers/Rpc/JobHostRpcWorkerChannelManager.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,13 @@ public Task<bool> ShutdownChannelIfExistsAsync(string channelId, Exception worke
4747
{
4848
if (channels.TryRemove(channelId, out IRpcWorkerChannel rpcChannel))
4949
{
50-
_logger.LogDebug("Disposing language worker channel with id:{workerId}", rpcChannel.Id);
50+
string id = rpcChannel.Id;
51+
_logger.LogDebug("Disposing language worker channel with id:{workerId}", id);
5152
rpcChannel.TryFailExecutions(workerException);
53+
5254
(rpcChannel as IDisposable)?.Dispose();
55+
_logger.LogDebug("Disposed language worker channel with id:{workerId}", id);
56+
5357
return Task.FromResult(true);
5458
}
5559
}

0 commit comments

Comments
 (0)