@@ -19,6 +19,7 @@ namespace Microsoft.Azure.WebJobs.Script
1919 public class ScriptHostManager : IDisposable
2020 {
2121 private readonly ScriptHostConfiguration _config ;
22+ private readonly IScriptHostFactory _scriptHostFactory ;
2223 private ScriptHost _currentInstance ;
2324
2425 // ScriptHosts are not thread safe, so be clear that only 1 thread at a time operates on each instance.
@@ -33,8 +34,14 @@ public class ScriptHostManager : IDisposable
3334 private TraceWriter _traceWriter ;
3435
3536 public ScriptHostManager ( ScriptHostConfiguration config )
37+ : this ( config , new ScriptHostFactory ( ) )
38+ {
39+ }
40+
41+ public ScriptHostManager ( ScriptHostConfiguration config , IScriptHostFactory scriptHostFactory )
3642 {
3743 _config = config ;
44+ _scriptHostFactory = scriptHostFactory ;
3845 }
3946
4047 /// <summary>
@@ -57,6 +64,7 @@ public ScriptHost Instance
5764 // host level configuration files change
5865 do
5966 {
67+ ScriptHost newInstance = null ;
6068 try
6169 {
6270 IsRunning = false ;
@@ -66,7 +74,7 @@ public ScriptHost Instance
6674 {
6775 HostId = _config . HostConfig . HostId
6876 } ;
69- ScriptHost newInstance = ScriptHost . Create ( _config ) ;
77+ newInstance = _scriptHostFactory . Create ( _config ) ;
7078 _traceWriter = newInstance . TraceWriter ;
7179
7280 // write any function initialization errors to the log file
@@ -108,6 +116,20 @@ public ScriptHost Instance
108116 _traceWriter . Error ( "A ScriptHost error occurred" , ex ) ;
109117 }
110118
119+ // If a ScriptHost instance was created before the exception was thrown
120+ // Orphan and cleanup that instance.
121+ if ( newInstance != null )
122+ {
123+ Orphan ( newInstance , forceStop : true )
124+ . ContinueWith ( t =>
125+ {
126+ if ( t . IsFaulted )
127+ {
128+ t . Exception . Handle ( e => true ) ;
129+ }
130+ } ) ;
131+ }
132+
111133 // Wait for a short period of time before restarting to
112134 // avoid cases where a host level config error might cause
113135 // a rapid restart cycle
@@ -132,21 +154,33 @@ private static void LogErrors(ScriptHost host)
132154 }
133155 }
134156
135- // Let the existing host instance finish currently executing functions.
136- private async Task Orphan ( ScriptHost instance )
157+ /// <summary>
158+ /// Remove the <see cref="ScriptHost"/> instance from the live instances collection,
159+ /// allowing it to finish currently executing functions before stopping and disposing of it.
160+ /// </summary>
161+ /// <param name="instance">The <see cref="ScriptHost"/> instance to remove</param>
162+ /// <param name="forceStop">Forces the call to stop and dispose of the instance, even if it isn't present in the live instances collection.</param>
163+ /// <returns></returns>
164+ private async Task Orphan ( ScriptHost instance , bool forceStop = false )
137165 {
138166 lock ( _liveInstances )
139167 {
140168 bool removed = _liveInstances . Remove ( instance ) ;
141- if ( ! removed )
169+ if ( ! forceStop && ! removed )
142170 {
143171 return ; // somebody else is handling it
144172 }
145173 }
146174
147- // this thread now owns the instance
148- await instance . StopAsync ( ) ;
149- instance . Dispose ( ) ;
175+ try
176+ {
177+ // this thread now owns the instance
178+ await instance . StopAsync ( ) ;
179+ }
180+ finally
181+ {
182+ instance . Dispose ( ) ;
183+ }
150184 }
151185
152186 public void Stop ( )
0 commit comments