Skip to content

Commit 67fb32f

Browse files
committed
WatchDirectories fix for Node.js (#954)
1 parent bf12270 commit 67fb32f

File tree

6 files changed

+66
-6
lines changed

6 files changed

+66
-6
lines changed

WebJobs.Script.sln

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{C9FCBC
353353
ProjectSection(SolutionItems) = preProject
354354
sample\Shared\Message.csx = sample\Shared\Message.csx
355355
sample\Shared\Order.csx = sample\Shared\Order.csx
356+
sample\Shared\test.js = sample\Shared\test.js
356357
EndProjectSection
357358
EndProject
358359
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ManualTrigger-CSharp", "ManualTrigger-CSharp", "{EB3A602B-4B32-4742-B4A2-39445BD2FBE3}"

sample/HttpTrigger/index.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
module.exports = function (context, req) {
1+
var test = require('../Shared/test');
2+
3+
module.exports = function (context, req) {
24
context.log('Node.js HTTP trigger function processed a request. Name=%s', req.query.name);
35

46
var headerValue = req.headers['test-header'];
@@ -19,9 +21,10 @@
1921
else {
2022
res = {
2123
status: 200,
22-
body: "Hello " + req.query.name,
24+
body: test.greeting(req.query.name),
2325
headers: {
24-
'Content-Type': 'text/plain'
26+
'Content-Type': 'text/plain',
27+
'Shared-Module': test.timestamp
2528
}
2629
};
2730
}

sample/Shared/test.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
var timestamp = new Date().getTime();
2+
3+
module.exports = {
4+
timestamp: timestamp,
5+
greeting: function (name) {
6+
return 'Hello ' + name;
7+
}
8+
};

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,11 @@ internal static object ConvertBindingValue(object value)
257257
return value;
258258
}
259259

260+
internal static void OnHostRestart()
261+
{
262+
ClearRequireCacheFunc(null).GetAwaiter().GetResult();
263+
}
264+
260265
protected override void OnScriptFileChanged(object sender, FileSystemEventArgs e)
261266
{
262267
if (_scriptFunc == null)

src/WebJobs.Script/Host/ScriptHost.cs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -310,9 +310,7 @@ protected virtual void Initialize()
310310
{
311311
TraceWriter.Info(string.Format(CultureInfo.InvariantCulture, "File change of type '{0}' detected for '{1}'", e.ChangeType, e.FullPath));
312312
TraceWriter.Info("Host configuration has changed. Signaling restart.");
313-
314-
// signal host restart
315-
_restartEvent.Set();
313+
RestartHost();
316314
};
317315
_restart = _restart.Debounce(500);
318316

@@ -407,6 +405,16 @@ internal static Collection<CustomAttributeBuilder> CreateTypeAttributes(ScriptHo
407405
return customAttributes;
408406
}
409407

408+
private void RestartHost()
409+
{
410+
// signal host restart
411+
_restartEvent.Set();
412+
413+
// whenever we're restarting the host, we want to let the Node
414+
// invoker know so it can clear the require cache, etc.
415+
NodeFunctionInvoker.OnHostRestart();
416+
}
417+
410418
/// <summary>
411419
/// Whenever the debug marker file changes we update our debug timeout
412420
/// </summary>

test/WebJobs.Script.Tests/SamplesEndToEndTests.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,41 @@ public async Task HttpTrigger_CustomRoute_Post_ReturnsExpectedResponse()
359359
Assert.Equal((string)product["name"], (string)resultProduct["name"]);
360360
}
361361

362+
[Fact]
363+
public async Task SharedDirectory_Node_ReloadsOnFileChange()
364+
{
365+
string uri = "api/httptrigger?code=hyexydhln844f2mb7hgsup2yf8dowlb0885mbiq1&name=Mathew";
366+
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, uri);
367+
HttpResponseMessage response = await _fixture.HttpClient.SendAsync(request);
368+
string initialTimestamp = response.Headers.GetValues("Shared-Module").First();
369+
370+
// make the request again and verify the timestamp is the same
371+
request = new HttpRequestMessage(HttpMethod.Get, uri);
372+
response = await _fixture.HttpClient.SendAsync(request);
373+
string timestamp = response.Headers.GetValues("Shared-Module").First();
374+
Assert.Equal(initialTimestamp, timestamp);
375+
376+
// now "touch" a file in the shared directory to trigger a restart
377+
string sharedModulePath = Path.Combine(_fixture.HostSettings.ScriptPath, "Shared\\test.js");
378+
File.SetLastWriteTimeUtc(sharedModulePath, DateTime.UtcNow);
379+
380+
// wait for the module to be reloaded
381+
await TestHelpers.Await(() =>
382+
{
383+
request = new HttpRequestMessage(HttpMethod.Get, uri);
384+
response = _fixture.HttpClient.SendAsync(request).GetAwaiter().GetResult();
385+
timestamp = response.Headers.GetValues("Shared-Module").First();
386+
return initialTimestamp != timestamp;
387+
}, timeout: 5000, pollingInterval: 1000);
388+
Assert.NotEqual(initialTimestamp, timestamp);
389+
390+
initialTimestamp = timestamp;
391+
request = new HttpRequestMessage(HttpMethod.Get, uri);
392+
response = await _fixture.HttpClient.SendAsync(request);
393+
timestamp = response.Headers.GetValues("Shared-Module").First();
394+
Assert.Equal(initialTimestamp, timestamp);
395+
}
396+
362397
[Fact]
363398
public async Task HttpTrigger_CSharp_CustomRoute_ReturnsExpectedResponse()
364399
{

0 commit comments

Comments
 (0)