Skip to content

Commit e3e2b2a

Browse files
committed
Disposal improvements for ScriptHost
1 parent 23f241b commit e3e2b2a

File tree

13 files changed

+133
-78
lines changed

13 files changed

+133
-78
lines changed

src/WebJobs.Script.WebHost/Diagnostics/FunctionInstanceLogger.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,7 @@ internal FunctionInstanceLogger(
7979
// This exception will cause the function to not get executed.
8080
throw new InvalidOperationException($"Missing function.json for '{shortName}'.");
8181
}
82-
FunctionLogger logInfo = descr.Invoker.LogInfo;
83-
state = new FunctionInstanceMonitor(descr.Metadata, _metrics, item.FunctionInstanceId, logInfo);
82+
state = new FunctionInstanceMonitor(descr.Metadata, _metrics, item.FunctionInstanceId, descr.Invoker.FunctionLogger);
8483

8584
item.Properties[Key] = state;
8685

src/WebJobs.Script/Binding/FunctionTraceBinderProvider.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ public static void Create(ExtensionConfigContext context)
2424
IBindingProvider inner = (IBindingProvider)Activator.CreateInstance(traceBinderType, loggerFactory);
2525

2626
Func<string, FunctionDescriptor> funcLookup = context.Config.GetService<Func<string, FunctionDescriptor>>();
27-
28-
// Func<string, FunctionDescriptor> funcLookup = null;
29-
3027
if (funcLookup != null && inner != null)
3128
{
3229
IBindingProvider wrapper = new Wrapper(inner, funcLookup);
@@ -86,10 +83,10 @@ private async Task<IValueProvider> WrapAsync(IValueProvider result, ValueBinding
8683
{
8784
var shortName = context.FunctionContext.MethodName;
8885
FunctionDescriptor descr = _parent._funcLookup(shortName);
89-
var logInfo = descr.Invoker.LogInfo;
86+
var functionLogger = descr.Invoker.FunctionLogger;
9087

9188
// This is the critical call
92-
trace = logInfo.CreateUserTraceWriter(trace);
89+
trace = functionLogger.CreateUserTraceWriter(trace);
9390

9491
return new SimpleValueProvider(typeof(TraceWriter), trace, result.ToInvokeString());
9592
}

src/WebJobs.Script/Description/FunctionInvokerBase.cs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,11 @@ public abstract class FunctionInvokerBase : IFunctionInvoker, IDisposable
2323
private bool _disposed = false;
2424
private IDisposable _fileChangeSubscription;
2525

26-
internal FunctionInvokerBase(ScriptHost host, FunctionMetadata functionMetadata)
27-
: this(host, functionMetadata, new FunctionLogger(host, functionMetadata.Name))
28-
{
29-
}
30-
31-
internal FunctionInvokerBase(ScriptHost host, FunctionMetadata functionMetadata, FunctionLogger logInfo)
26+
internal FunctionInvokerBase(ScriptHost host, FunctionMetadata functionMetadata, string logDirName = null)
3227
{
3328
Host = host;
3429
Metadata = functionMetadata;
35-
LogInfo = logInfo;
30+
FunctionLogger = new FunctionLogger(host, logDirName ?? functionMetadata.Name);
3631
}
3732

3833
protected static IDictionary<string, object> PrimaryHostTraceProperties { get; }
@@ -46,15 +41,15 @@ internal FunctionInvokerBase(ScriptHost host, FunctionMetadata functionMetadata,
4641

4742
public ScriptHost Host { get; }
4843

49-
public FunctionLogger LogInfo { get; }
44+
public FunctionLogger FunctionLogger { get; }
5045

5146
public FunctionMetadata Metadata { get; }
5247

53-
protected TraceWriter TraceWriter => LogInfo.TraceWriter;
48+
protected TraceWriter TraceWriter => FunctionLogger.TraceWriter;
5449

55-
protected ILogger Logger => LogInfo.Logger;
50+
protected ILogger Logger => FunctionLogger.Logger;
5651

57-
public TraceWriter FileTraceWriter => LogInfo.FileTraceWriter;
52+
public TraceWriter FileTraceWriter => FunctionLogger.FileTraceWriter;
5853

5954
/// <summary>
6055
/// All unhandled invocation exceptions will flow through this method.
@@ -70,7 +65,7 @@ public virtual void OnError(Exception ex)
7065

7166
protected virtual void TraceError(string errorMessage)
7267
{
73-
LogInfo.TraceError(errorMessage);
68+
FunctionLogger.TraceError(errorMessage);
7469
}
7570

7671
protected bool InitializeFileWatcherIfEnabled()
@@ -155,7 +150,7 @@ internal void TraceCompilationDiagnostics(ImmutableArray<Diagnostic> diagnostics
155150
return;
156151
}
157152

158-
TraceWriter traceWriter = LogInfo.TraceWriter;
153+
TraceWriter traceWriter = FunctionLogger.TraceWriter;
159154
IDictionary<string, object> properties = PrimaryHostTraceProperties;
160155

161156
if (!logTarget.HasFlag(LogTargets.User))
@@ -208,7 +203,7 @@ protected virtual void Dispose(bool disposing)
208203
{
209204
_fileChangeSubscription?.Dispose();
210205

211-
(LogInfo.TraceWriter as IDisposable)?.Dispose();
206+
FunctionLogger.Dispose();
212207
}
213208

214209
_disposed = true;

src/WebJobs.Script/Description/FunctionLogger.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the MIT License. See License.txt in the project root for license information.
33

4+
using System;
45
using System.Collections.Generic;
56
using System.Diagnostics;
67
using Microsoft.Azure.WebJobs.Host;
@@ -11,8 +12,10 @@ namespace Microsoft.Azure.WebJobs.Script.Description
1112
{
1213
// Each function can get its own log stream.
1314
// Static per-function logging information.
14-
public class FunctionLogger
15+
public class FunctionLogger : IDisposable
1516
{
17+
private bool _disposed = false;
18+
1619
public FunctionLogger(ScriptHost host, string functionName, string logDirName = null)
1720
{
1821
// Function file logging is only done conditionally
@@ -82,5 +85,25 @@ public void LogFunctionResult(bool success, string invocationId, long elapsedMs)
8285
TraceWriter.Trace(message, traceWriterLevel, null);
8386
Logger?.Log(logLevel, new EventId(0), message, null, (s, e) => s);
8487
}
88+
89+
protected virtual void Dispose(bool disposing)
90+
{
91+
if (!_disposed)
92+
{
93+
if (disposing)
94+
{
95+
(FileTraceWriter as IDisposable)?.Dispose();
96+
(TraceWriter as IDisposable)?.Dispose();
97+
}
98+
99+
_disposed = true;
100+
}
101+
}
102+
103+
public void Dispose()
104+
{
105+
Dispose(true);
106+
GC.SuppressFinalize(this);
107+
}
85108
}
86109
}

src/WebJobs.Script/Description/IFunctionInvoker.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public interface IFunctionInvoker
1111
/// <summary>
1212
/// Gets logging information for this function.
1313
/// </summary>
14-
FunctionLogger LogInfo { get; }
14+
FunctionLogger FunctionLogger { get; }
1515

1616
/// <summary>
1717
/// Invoke the function using the specified parameters.

src/WebJobs.Script/Description/Node/NodeFunctionInvoker.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,16 @@ private async Task ReloadScriptAsync()
336336
}
337337
}
338338

339+
protected override void Dispose(bool disposing)
340+
{
341+
base.Dispose(disposing);
342+
343+
if (disposing)
344+
{
345+
_functionLoader.Dispose();
346+
}
347+
}
348+
339349
private async Task<Dictionary<string, object>> CreateScriptExecutionContextAsync(object input, DataType dataType, TraceWriter traceWriter, FunctionInvocationContext invocationContext)
340350
{
341351
// create a TraceWriter wrapper that can be exposed to Node.js

src/WebJobs.Script/Description/Proxies/ProxyFunctionInvoker.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,9 @@
22
// Licensed under the MIT License. See License.txt in the project root for license information.
33

44
using System;
5-
using System.Collections.Generic;
65
using System.Linq;
7-
using System.Management.Automation;
86
using System.Net.Http;
9-
using System.Text;
107
using System.Threading.Tasks;
11-
using Microsoft.Azure.AppService.Proxy.Client.Contract;
128

139
namespace Microsoft.Azure.WebJobs.Script.Description
1410
{
@@ -17,7 +13,7 @@ internal class ProxyFunctionInvoker : FunctionInvokerBase
1713
private ProxyClientExecutor _proxyClient;
1814

1915
public ProxyFunctionInvoker(ScriptHost host, FunctionMetadata functionMetadata, ProxyClientExecutor proxyClient)
20-
: base(host, functionMetadata, new FunctionLogger(host, functionMetadata.Name, logDirName: "Proxy"))
16+
: base(host, functionMetadata, logDirName: "Proxy")
2117
{
2218
_proxyClient = proxyClient;
2319
}

src/WebJobs.Script/GlobalSuppressions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,4 +229,5 @@
229229
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Dir", Scope = "member", Target = "Microsoft.Azure.WebJobs.Script.Description.FunctionLogger.#.ctor(Microsoft.Azure.WebJobs.Script.ScriptHost,System.String,System.String)")]
230230
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Dir", Scope = "member", Target = "Microsoft.Azure.WebJobs.Script.IFunctionTraceWriterFactory.#Create(System.String,System.String)")]
231231
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Scope = "member", Target = "Microsoft.Azure.WebJobs.Script.ScriptHost.#Create(Microsoft.Azure.WebJobs.Script.IScriptHostEnvironment,Microsoft.Azure.WebJobs.Script.Eventing.IScriptEventManager,Microsoft.Azure.WebJobs.Script.ScriptHostConfiguration,Microsoft.Azure.WebJobs.Script.Config.ScriptSettingsManager,Microsoft.Azure.WebJobs.Script.Description.ProxyClientExecutor)")]
232-
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom", Scope = "member", Target = "Microsoft.Azure.WebJobs.Script.Binding.ExtensionLoader.#LoadCustomExtensions(System.String)")]
232+
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom", Scope = "member", Target = "Microsoft.Azure.WebJobs.Script.Binding.ExtensionLoader.#LoadCustomExtensions(System.String)")]
233+
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "<FunctionLogger>k__BackingField", Scope = "member", Target = "Microsoft.Azure.WebJobs.Script.Description.FunctionInvokerBase.#Dispose(System.Boolean)")]

src/WebJobs.Script/Host/PrimaryHostCoordinator.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,10 @@ private void ResetLease()
203203

204204
private void SetTimerInterval(TimeSpan interval, TimeSpan? dueTimeout = null)
205205
{
206-
_timer.Change(dueTimeout ?? interval, interval);
206+
if (!_disposed)
207+
{
208+
_timer.Change(dueTimeout ?? interval, interval);
209+
}
207210
}
208211

209212
private void TryReleaseLeaseIfOwned()

0 commit comments

Comments
 (0)