Skip to content

Commit 0a657a5

Browse files
authored
Drain mode cleanup: remove GET, return 202 Accepted (#7876)
1 parent 3d0eba2 commit 0a657a5

File tree

6 files changed

+141
-8
lines changed

6 files changed

+141
-8
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"bindings": [
3+
{
4+
"type": "httpTrigger",
5+
"name": "req",
6+
"direction": "in",
7+
"methods": [ "get" ]
8+
},
9+
{
10+
"type": "http",
11+
"name": "$return",
12+
"direction": "out"
13+
}
14+
]
15+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System.Net;
2+
using System.Threading;
3+
using Microsoft.AspNetCore.Mvc;
4+
using Microsoft.Extensions.Primitives;
5+
6+
public static async Task<IActionResult> Run(HttpRequest req, ILogger log, CancellationToken token)
7+
{
8+
log.LogInformation("C# HTTP trigger cancellation function processing a request.");
9+
10+
try
11+
{
12+
await Task.Delay(10000, token);
13+
log.LogInformation("Function invocation successful.");
14+
return new OkResult();
15+
16+
}
17+
catch (OperationCanceledException)
18+
{
19+
log.LogInformation("Function invocation cancelled.");
20+
return new NotFoundResult();
21+
}
22+
catch (Exception e)
23+
{
24+
return new StatusCodeResult(500);
25+
}
26+
}

src/WebJobs.Script.WebHost/Controllers/HostController.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@ public async Task<IActionResult> GetHostStatus([FromServices] IScriptHostManager
105105
return Ok(status);
106106
}
107107

108-
[HttpGet]
109108
[HttpPost]
110109
[Route("admin/host/drain")]
111110
[Authorize(Policy = PolicyNames.AdminAuthLevelOrInternal)]
@@ -132,7 +131,7 @@ public async Task<IActionResult> Drain([FromServices] IScriptHostManager scriptH
132131

133132
_drainModeSemaphore.Release();
134133
});
135-
return Ok();
134+
return Accepted();
136135
}
137136

138137
[HttpGet]
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
using Microsoft.Azure.WebJobs.Script.WebHost.Models;
2+
using Microsoft.Azure.WebJobs.Script.Workers.Rpc;
3+
using Microsoft.WebJobs.Script.Tests;
4+
using Newtonsoft.Json;
5+
using Newtonsoft.Json.Linq;
6+
using System;
7+
using System.IO;
8+
using System.Net;
9+
using System.Threading;
10+
using System.Threading.Tasks;
11+
using Xunit;
12+
13+
namespace Microsoft.Azure.WebJobs.Script.Tests.EndToEnd
14+
{
15+
[Trait(TestTraits.Category, TestTraits.EndToEnd)]
16+
[Trait(TestTraits.Group, TestTraits.DrainModeEndToEnd)]
17+
public class DrainModeEndToEndTests : DrainTestFixture
18+
{
19+
[Fact]
20+
public async Task RunningHost_EnableDrainMode_ReturnsAccepted()
21+
{
22+
// Validate the drain state is "Disabled" initially
23+
var response = await SamplesTestHelpers.InvokeDrainStatus(this);
24+
var responseString = response.Content.ReadAsStringAsync().Result;
25+
var drainStatus = JsonConvert.DeserializeObject<DrainModeStatus>(responseString);
26+
27+
Assert.Equal(drainStatus.State, DrainModeState.Disabled);
28+
29+
// Validate ability to call HttpTrigger without issues
30+
response = await SamplesTestHelpers.InvokeHttpTrigger(this, "HttpTrigger");
31+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
32+
33+
// Put the host in drain mode and validate returns Accepted
34+
response = await SamplesTestHelpers.InvokeDrain(this);
35+
Assert.Equal(HttpStatusCode.Accepted, response.StatusCode);
36+
37+
// Validate the drain state is changed to "Completed"
38+
response = await SamplesTestHelpers.InvokeDrainStatus(this);
39+
responseString = response.Content.ReadAsStringAsync().Result;
40+
drainStatus = JsonConvert.DeserializeObject<DrainModeStatus>(responseString);
41+
42+
Assert.Equal(DrainModeState.Completed, drainStatus.State);
43+
44+
// Validate HttpTrigger function is still working
45+
response = await SamplesTestHelpers.InvokeHttpTrigger(this, "HttpTrigger");
46+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
47+
}
48+
49+
[Fact]
50+
public async Task RunningHost_EnableDrainMode_FunctionInvocationCancelled_ReturnsNotFound()
51+
{
52+
// Validate the drain state is "Disabled" initially
53+
var response = await SamplesTestHelpers.InvokeDrainStatus(this);
54+
var responseString = response.Content.ReadAsStringAsync().Result;
55+
var drainStatus = JsonConvert.DeserializeObject<DrainModeStatus>(responseString);
56+
57+
Assert.Equal(drainStatus.State, DrainModeState.Disabled);
58+
59+
_ = Task.Run(async () =>
60+
{
61+
// Put the host in drain mode
62+
await TestHelpers.Await(async () =>
63+
{
64+
response = await SamplesTestHelpers.InvokeDrain(this);
65+
Assert.Equal(HttpStatusCode.Accepted, response.StatusCode);
66+
return true;
67+
}, 10000);
68+
69+
});
70+
71+
// Call function with cancellation token handler
72+
response = await SamplesTestHelpers.InvokeHttpTrigger(this, "HttpTrigger-Cancellation");
73+
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
74+
}
75+
}
76+
77+
public class DrainTestFixture : EndToEndTestFixture
78+
{
79+
static DrainTestFixture()
80+
{
81+
}
82+
83+
public DrainTestFixture()
84+
: base(Path.Combine(Environment.CurrentDirectory, "..", "..", "..", "..", "..", "sample", "CSharp"), "samples", RpcWorkerConstants.DotNetLanguageWorkerName)
85+
{
86+
}
87+
88+
public override void ConfigureScriptHost(IWebJobsBuilder webJobsBuilder)
89+
{
90+
base.ConfigureScriptHost(webJobsBuilder);
91+
}
92+
}
93+
}

test/WebJobs.Script.Tests.Integration/WebHostEndToEnd/DrainModeStatusEndToEndTests.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace Microsoft.Azure.WebJobs.Script.Tests.EndToEnd
1616
{
1717
[Trait(TestTraits.Category, TestTraits.EndToEnd)]
1818
[Trait(TestTraits.Group, TestTraits.DrainModeEndToEnd)]
19-
public class DrainModeStatusEndToEndTests : DrainTestFixture
19+
public class DrainModeStatusEndToEndTests : DrainStatusTestFixture
2020
{
2121
[Fact]
2222
public async Task DrainStatus_RunningHost_ReturnsExpected()
@@ -26,7 +26,7 @@ public async Task DrainStatus_RunningHost_ReturnsExpected()
2626
var responseString = response.Content.ReadAsStringAsync().Result;
2727
var status = JsonConvert.DeserializeObject<DrainModeStatus>(responseString);
2828

29-
Assert.Equal(status.State, DrainModeState.Disabled);
29+
Assert.Equal(DrainModeState.Disabled, status.State);
3030

3131
ManualResetEvent resetEvent = new ManualResetEvent(false);
3232
_ = Task.Run(async () =>
@@ -64,13 +64,13 @@ await TestHelpers.Await(async () =>
6464
}
6565
}
6666

67-
public class DrainTestFixture : EndToEndTestFixture
67+
public class DrainStatusTestFixture : EndToEndTestFixture
6868
{
69-
static DrainTestFixture()
69+
static DrainStatusTestFixture()
7070
{
7171
}
7272

73-
public DrainTestFixture()
73+
public DrainStatusTestFixture()
7474
: base(Path.Combine(Environment.CurrentDirectory, "..", "..", "..", "..", "..", "sample", "NodeDrain"), "samples", RpcWorkerConstants.NodeLanguageWorkerName)
7575
{
7676
}

test/WebJobs.Script.Tests.Integration/WebHostEndToEnd/SamplesEndToEndTests_CSharp.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ public async Task ListFunctions_Succeeds()
512512
var response = await _fixture.Host.HttpClient.SendAsync(request);
513513
var metadata = (await response.Content.ReadAsAsync<IEnumerable<FunctionMetadataResponse>>()).ToArray();
514514

515-
Assert.Equal(16, metadata.Length);
515+
Assert.Equal(17, metadata.Length);
516516
var function = metadata.Single(p => p.Name == "HttpTrigger-CustomRoute");
517517
Assert.Equal("https://somewebsite.azurewebsites.net/api/csharp/products/{category:alpha?}/{id:int?}/{extra?}", function.InvokeUrlTemplate.ToString());
518518

0 commit comments

Comments
 (0)