@@ -16,37 +16,37 @@ namespace Microsoft.Azure.WebJobs.Script
16
16
public class ScriptHost : JobHost
17
17
{
18
18
private const string HostAssemblyName = "ScriptHost" ;
19
+ private FileSystemWatcher _fileWatcher ;
19
20
20
- protected ScriptHost ( JobHostConfiguration config , ScriptHostConfiguration scriptConfig )
21
- : base ( config )
21
+ protected ScriptHost ( ScriptHostConfiguration scriptConfig )
22
+ : base ( scriptConfig . HostConfig )
22
23
{
23
- HostConfig = config ;
24
24
ScriptConfig = scriptConfig ;
25
25
}
26
26
27
- public JobHostConfiguration HostConfig { get ; private set ; }
28
-
29
27
public ScriptHostConfiguration ScriptConfig { get ; private set ; }
30
28
29
+ public bool Restart { get ; private set ; }
30
+
31
31
protected virtual void Initialize ( )
32
32
{
33
33
List < FunctionDescriptorProvider > descriptionProviders = new List < FunctionDescriptorProvider > ( )
34
34
{
35
- new ScriptFunctionDescriptorProvider ( HostConfig , ScriptConfig . RootPath ) ,
36
- new NodeFunctionDescriptorProvider ( HostConfig , ScriptConfig . RootPath )
35
+ new ScriptFunctionDescriptorProvider ( ScriptConfig ) ,
36
+ new NodeFunctionDescriptorProvider ( this , ScriptConfig )
37
37
} ;
38
38
39
- if ( HostConfig . IsDevelopment )
39
+ if ( ScriptConfig . HostConfig . IsDevelopment )
40
40
{
41
- HostConfig . UseDevelopmentSettings ( ) ;
41
+ ScriptConfig . HostConfig . UseDevelopmentSettings ( ) ;
42
42
}
43
43
44
44
// read host.json and apply to JobHostConfiguration
45
45
string hostConfigFilePath = Path . Combine ( ScriptConfig . RootPath , "host.json" ) ;
46
46
Console . WriteLine ( string . Format ( "Reading host configuration file '{0}'" , hostConfigFilePath ) ) ;
47
47
string json = File . ReadAllText ( hostConfigFilePath ) ;
48
48
JObject hostConfig = JObject . Parse ( json ) ;
49
- ApplyConfiguration ( hostConfig , HostConfig ) ;
49
+ ApplyConfiguration ( hostConfig , ScriptConfig ) ;
50
50
51
51
// read all script functions and apply to JobHostConfiguration
52
52
Collection < FunctionDescriptor > functions = ReadFunctions ( ScriptConfig , descriptionProviders ) ;
@@ -57,8 +57,33 @@ protected virtual void Initialize()
57
57
List < Type > types = new List < Type > ( ) ;
58
58
types . Add ( type ) ;
59
59
60
- HostConfig . TypeLocator = new TypeLocator ( types ) ;
61
- HostConfig . NameResolver = new NameResolver ( ) ;
60
+ ScriptConfig . HostConfig . TypeLocator = new TypeLocator ( types ) ;
61
+ ScriptConfig . HostConfig . NameResolver = new NameResolver ( ) ;
62
+
63
+ if ( ScriptConfig . WatchFiles )
64
+ {
65
+ _fileWatcher = new FileSystemWatcher ( ScriptConfig . RootPath , "*.json" )
66
+ {
67
+ IncludeSubdirectories = true ,
68
+ EnableRaisingEvents = true
69
+ } ;
70
+ _fileWatcher . Changed += OnConfigurationFileChanged ;
71
+ }
72
+ }
73
+
74
+ private void StopAndRestart ( )
75
+ {
76
+ if ( Restart )
77
+ {
78
+ // we've already received a restart call
79
+ return ;
80
+ }
81
+
82
+ Console . WriteLine ( "The host configuration file has changed. Restarting." ) ;
83
+
84
+ // Flag for restart and stop the host.
85
+ Restart = true ;
86
+ Stop ( ) ;
62
87
}
63
88
64
89
public static ScriptHost Create ( ScriptHostConfiguration scriptConfig = null )
@@ -76,8 +101,7 @@ public static ScriptHost Create(ScriptHostConfiguration scriptConfig = null)
76
101
scriptConfig . RootPath = Path . Combine ( Environment . CurrentDirectory , scriptConfig . RootPath ) ;
77
102
}
78
103
79
- JobHostConfiguration config = new JobHostConfiguration ( ) ;
80
- ScriptHost scriptHost = new ScriptHost ( config , scriptConfig ) ;
104
+ ScriptHost scriptHost = new ScriptHost ( scriptConfig ) ;
81
105
scriptHost . Initialize ( ) ;
82
106
83
107
return scriptHost ;
@@ -180,14 +204,22 @@ internal static Collection<FunctionDescriptor> ReadFunctions(List<FunctionFolder
180
204
return functionDescriptors ;
181
205
}
182
206
183
- internal static void ApplyConfiguration ( JObject config , JobHostConfiguration jobHostConfig )
207
+ internal static void ApplyConfiguration ( JObject config , ScriptHostConfiguration scriptConfig )
184
208
{
209
+ JobHostConfiguration hostConfig = scriptConfig . HostConfig ;
210
+
185
211
JToken hostId = ( JToken ) config [ "id" ] ;
186
212
if ( hostId == null )
187
213
{
188
214
throw new InvalidOperationException ( "An 'id' must be specified in the host configuration." ) ;
189
215
}
190
- jobHostConfig . HostId = ( string ) hostId ;
216
+ hostConfig . HostId = ( string ) hostId ;
217
+
218
+ JToken watchFiles = ( JToken ) config [ "watchFiles" ] ;
219
+ if ( watchFiles != null && watchFiles . Type == JTokenType . Boolean )
220
+ {
221
+ scriptConfig . WatchFiles = ( bool ) watchFiles ;
222
+ }
191
223
192
224
// Apply Queues configuration
193
225
JObject configSection = ( JObject ) config [ "queues" ] ;
@@ -196,19 +228,19 @@ internal static void ApplyConfiguration(JObject config, JobHostConfiguration job
196
228
{
197
229
if ( configSection . TryGetValue ( "maxPollingInterval" , out value ) )
198
230
{
199
- jobHostConfig . Queues . MaxPollingInterval = TimeSpan . FromMilliseconds ( ( int ) value ) ;
231
+ hostConfig . Queues . MaxPollingInterval = TimeSpan . FromMilliseconds ( ( int ) value ) ;
200
232
}
201
233
if ( configSection . TryGetValue ( "batchSize" , out value ) )
202
234
{
203
- jobHostConfig . Queues . BatchSize = ( int ) value ;
235
+ hostConfig . Queues . BatchSize = ( int ) value ;
204
236
}
205
237
if ( configSection . TryGetValue ( "maxDequeueCount" , out value ) )
206
238
{
207
- jobHostConfig . Queues . MaxDequeueCount = ( int ) value ;
239
+ hostConfig . Queues . MaxDequeueCount = ( int ) value ;
208
240
}
209
241
if ( configSection . TryGetValue ( "newBatchThreshold" , out value ) )
210
242
{
211
- jobHostConfig . Queues . NewBatchThreshold = ( int ) value ;
243
+ hostConfig . Queues . NewBatchThreshold = ( int ) value ;
212
244
}
213
245
}
214
246
@@ -219,23 +251,23 @@ internal static void ApplyConfiguration(JObject config, JobHostConfiguration job
219
251
{
220
252
if ( configSection . TryGetValue ( "lockPeriod" , out value ) )
221
253
{
222
- jobHostConfig . Singleton . LockPeriod = TimeSpan . Parse ( ( string ) value ) ;
254
+ hostConfig . Singleton . LockPeriod = TimeSpan . Parse ( ( string ) value ) ;
223
255
}
224
256
if ( configSection . TryGetValue ( "listenerLockPeriod" , out value ) )
225
257
{
226
- jobHostConfig . Singleton . ListenerLockPeriod = TimeSpan . Parse ( ( string ) value ) ;
258
+ hostConfig . Singleton . ListenerLockPeriod = TimeSpan . Parse ( ( string ) value ) ;
227
259
}
228
260
if ( configSection . TryGetValue ( "listenerLockRecoveryPollingInterval" , out value ) )
229
261
{
230
- jobHostConfig . Singleton . ListenerLockRecoveryPollingInterval = TimeSpan . Parse ( ( string ) value ) ;
262
+ hostConfig . Singleton . ListenerLockRecoveryPollingInterval = TimeSpan . Parse ( ( string ) value ) ;
231
263
}
232
264
if ( configSection . TryGetValue ( "lockAcquisitionTimeout" , out value ) )
233
265
{
234
- jobHostConfig . Singleton . LockAcquisitionTimeout = TimeSpan . Parse ( ( string ) value ) ;
266
+ hostConfig . Singleton . LockAcquisitionTimeout = TimeSpan . Parse ( ( string ) value ) ;
235
267
}
236
268
if ( configSection . TryGetValue ( "lockAcquisitionPollingInterval" , out value ) )
237
269
{
238
- jobHostConfig . Singleton . LockAcquisitionPollingInterval = TimeSpan . Parse ( ( string ) value ) ;
270
+ hostConfig . Singleton . LockAcquisitionPollingInterval = TimeSpan . Parse ( ( string ) value ) ;
239
271
}
240
272
}
241
273
@@ -250,7 +282,7 @@ internal static void ApplyConfiguration(JObject config, JobHostConfiguration job
250
282
sbConfig . MessageOptions . MaxConcurrentCalls = ( int ) value ;
251
283
}
252
284
}
253
- jobHostConfig . UseServiceBus ( sbConfig ) ;
285
+ hostConfig . UseServiceBus ( sbConfig ) ;
254
286
255
287
// Apply Tracing configuration
256
288
configSection = ( JObject ) config [ "tracing" ] ;
@@ -259,7 +291,7 @@ internal static void ApplyConfiguration(JObject config, JobHostConfiguration job
259
291
TraceLevel consoleLevel ;
260
292
if ( Enum . TryParse < TraceLevel > ( ( string ) value , true , out consoleLevel ) )
261
293
{
262
- jobHostConfig . Tracing . ConsoleLevel = consoleLevel ;
294
+ hostConfig . Tracing . ConsoleLevel = consoleLevel ;
263
295
}
264
296
}
265
297
@@ -270,9 +302,33 @@ internal static void ApplyConfiguration(JObject config, JobHostConfiguration job
270
302
{
271
303
webHooksConfig = new WebHooksConfiguration ( ( int ) value ) ;
272
304
}
273
- jobHostConfig . UseWebHooks ( webHooksConfig ) ;
305
+ hostConfig . UseWebHooks ( webHooksConfig ) ;
306
+
307
+ hostConfig . UseTimers ( ) ;
308
+ }
309
+
310
+ private void OnConfigurationFileChanged ( object sender , FileSystemEventArgs e )
311
+ {
312
+ string fileName = Path . GetFileName ( e . Name ) ;
313
+
314
+ if ( ! Restart &&
315
+ ( ( string . Compare ( fileName , "host.json" ) == 0 ) || string . Compare ( fileName , "function.json" ) == 0 ) )
316
+ {
317
+ StopAndRestart ( ) ;
318
+ }
319
+ }
320
+
321
+ protected override void Dispose ( bool disposing )
322
+ {
323
+ if ( disposing )
324
+ {
325
+ if ( _fileWatcher != null )
326
+ {
327
+ _fileWatcher . Dispose ( ) ;
328
+ }
329
+ }
274
330
275
- jobHostConfig . UseTimers ( ) ;
331
+ base . Dispose ( disposing ) ;
276
332
}
277
333
}
278
334
}
0 commit comments