@@ -19,6 +19,7 @@ namespace Microsoft.Azure.WebJobs.Script
19
19
public class ScriptHostManager : IDisposable
20
20
{
21
21
private readonly ScriptHostConfiguration _config ;
22
+ private readonly IScriptHostFactory _scriptHostFactory ;
22
23
private ScriptHost _currentInstance ;
23
24
24
25
// 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
33
34
private TraceWriter _traceWriter ;
34
35
35
36
public ScriptHostManager ( ScriptHostConfiguration config )
37
+ : this ( config , new ScriptHostFactory ( ) )
38
+ {
39
+ }
40
+
41
+ public ScriptHostManager ( ScriptHostConfiguration config , IScriptHostFactory scriptHostFactory )
36
42
{
37
43
_config = config ;
44
+ _scriptHostFactory = scriptHostFactory ;
38
45
}
39
46
40
47
/// <summary>
@@ -57,6 +64,7 @@ public ScriptHost Instance
57
64
// host level configuration files change
58
65
do
59
66
{
67
+ ScriptHost newInstance = null ;
60
68
try
61
69
{
62
70
IsRunning = false ;
@@ -66,7 +74,7 @@ public ScriptHost Instance
66
74
{
67
75
HostId = _config . HostConfig . HostId
68
76
} ;
69
- ScriptHost newInstance = ScriptHost . Create ( _config ) ;
77
+ newInstance = _scriptHostFactory . Create ( _config ) ;
70
78
_traceWriter = newInstance . TraceWriter ;
71
79
72
80
// write any function initialization errors to the log file
@@ -108,6 +116,20 @@ public ScriptHost Instance
108
116
_traceWriter . Error ( "A ScriptHost error occurred" , ex ) ;
109
117
}
110
118
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
+
111
133
// Wait for a short period of time before restarting to
112
134
// avoid cases where a host level config error might cause
113
135
// a rapid restart cycle
@@ -132,21 +154,33 @@ private static void LogErrors(ScriptHost host)
132
154
}
133
155
}
134
156
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 )
137
165
{
138
166
lock ( _liveInstances )
139
167
{
140
168
bool removed = _liveInstances . Remove ( instance ) ;
141
- if ( ! removed )
169
+ if ( ! forceStop && ! removed )
142
170
{
143
171
return ; // somebody else is handling it
144
172
}
145
173
}
146
174
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
+ }
150
184
}
151
185
152
186
public void Stop ( )
0 commit comments