Skip to content

Commit 9e3e169

Browse files
authored
- introduce preferred success status code cache for web result endpoints to improve performance (#16)
- update benchmark test results and README file - bump version
1 parent fdce832 commit 9e3e169

10 files changed

+385
-62
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@
1818
<PackageLicenseExpression>MIT</PackageLicenseExpression>
1919
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
2020

21-
<Version>0.6.5</Version>
21+
<Version>0.6.6</Version>
2222
</PropertyGroup>
2323
</Project>

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ app.Run();
7070

7171
A [MinimalEndpoint](#minimalendpoint) is the most straighforward way to define a Minimal Api in REPR format.
7272

73-
Configuration of each endpoint implementation starts with calling one of the MapGet, MapPost, MapPut, MapDelete and MapPatch methods with a route pattern string. The return from any of these methods, a RouteHandlerBuilder instance, can be used to further customize the endpoint like a regular Minimal Api.
73+
Configuration of each endpoint implementation starts with calling one of the MapGet, MapPost, MapPut, MapDelete and MapPatch methods with a route pattern string. The return from any of these methods, a RouteHandlerBuilder instance, can be used to further customize the endpoint similar to a Minimal Api.
7474

7575
The request is processed in 'HandleAsync' method. Request is passed to handler method as parameter after validation (if a validator is registered for request model). Handler method returns a response model or a string or a Minimal Api IResult based response.
7676

@@ -250,10 +250,10 @@ internal class UploadBook
250250

251251
### Route groups
252252

253-
By default, all endpoints are mapped under root route group. It is possible to define route groups similar to using 'MapGroup' extension method used to map Minimal Apis under a group. Since endpoints are configured by endpoint basis in the 'Configure' method of each endpoint, the approach is a little different than regular Minimal Apis, but these are still Minimal Api route groups and can be configured by any extension method of RouteGroupBuilder. Route groups are also subject to auto discovery and registration, similar to endpoints.
253+
By default, all endpoints are mapped under root route group. It is possible to define route groups similar to using 'MapGroup' extension method used to map Minimal Apis under a group. Since endpoints are configured by endpoint basis in the 'Configure' method of each endpoint, the approach is a little different than configuring a Minimal Api. But route group configuration still utilize Minimal Api route groups and can be decorated by any extension method of RouteGroupBuilder. Route groups are also subject to auto discovery and registration, similar to endpoints.
254254

255255
- [Create a route group implementation](./samples/ShowcaseWebApi/Features/FeaturesRouteGroup.cs) by inheriting RouteGroupConfigurator and implementing 'Configure' method,
256-
- Configuration of each route group implementation starts with calling MapGroup method with a route pattern prefix. The return of 'MapGroup' method, a RouteGroupBuilder instance, can be used to further customize the route group like a regular Minimal Api route group.
256+
- Configuration of each route group implementation starts with calling MapGroup method with a route pattern prefix. The return of 'MapGroup' method, a RouteGroupBuilder instance, can be used to further customize the route group like any Minimal Api route group.
257257
- Apply MapToGroup attribute to either other [route group](./samples/ShowcaseWebApi/Features/Books/Configuration/BooksV1RouteGroup.cs) or [endpoint](./samples/ShowcaseWebApi/Features/Books/CreateBook.cs) classes that will be mapped under created route group. Use type of the new route group implementation as GroupType parameter to the attribute.
258258

259259
Following sample creates a parent route group (FeaturesRouteGroup), a child route group under it (BooksV1RouteGroup) and maps an endpoint (CreateBook) to child route group. Group configuration methods used for this particular sample are all part of Minimal Apis ecosystem and are under [Asp.Versioning](https://github.com/dotnet/aspnet-api-versioning).
@@ -347,13 +347,13 @@ internal class DisabledCustomerFeature
347347

348348
## Performance
349349

350-
WebResultEndpoints have a slight overhead (3-4%) over regular Minimal Apis on request/sec metric under load tests with 100 virtual users.
351-
352-
MinimalEndpoints perform about same as regular Minimal Apis.
350+
Under load tests with 100 virtual users:
351+
- MinimalEndpoints perform nearly the same (~1%) as Minimal Apis,
352+
- WebResultEndpoints introduce a slight overhead (~2%) compared to Minimal Apis in terms of requests per second.
353353

354354
The web apis called for tests, perform only in-process operations like resolving dependency, validating input, calling local methods with no network or disk I/O.
355355

356-
See [test results](./samples/BenchmarkWebApi/BenchmarkFiles/Results/0.6.5/inprocess_benchmark_results.txt) under [BenchmarkFiles](https://github.com/modabas/ModEndpoints/tree/main/samples/BenchmarkWebApi/BenchmarkFiles) folder of BenchmarkWebApi project for detailed results and test scripts.
356+
See [test results](./samples/BenchmarkWebApi/BenchmarkFiles/Results/0.6.6/inprocess_benchmark_results.txt) under [BenchmarkFiles](https://github.com/modabas/ModEndpoints/tree/main/samples/BenchmarkWebApi/BenchmarkFiles) folder of BenchmarkWebApi project for detailed results and test scripts.
357357

358358
## Endpoint Types
359359

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
 k6  .\k6 run minimal_api_basic.js
2+
3+
/\ Grafana /‾‾/
4+
/\ / \ |\ __ / /
5+
/ \/ \ | |/ / / ‾‾\
6+
/ \ | ( | (‾) |
7+
/ __________ \ |_|\_\ \_____/
8+
9+
execution: local
10+
script: minimal_api_basic.js
11+
output: -
12+
13+
scenarios: (100.00%) 1 scenario, 100 max VUs, 2m20s max duration (incl. graceful stop):
14+
* default: Up to 100 looping VUs for 1m50s over 3 stages (gracefulRampDown: 30s, gracefulStop: 30s)
15+
16+
17+
✓ status was 200
18+
19+
checks.........................: 100.00% 8333889 out of 8333889
20+
data_received..................: 1.4 GB 13 MB/s
21+
data_sent......................: 850 MB 7.7 MB/s
22+
http_req_blocked...............: avg=3.33µs min=0s med=0s max=49.27ms p(90)=0s p(95)=0s
23+
http_req_connecting............: avg=8ns min=0s med=0s max=4.52ms p(90)=0s p(95)=0s
24+
✓ http_req_duration..............: avg=903.53µs min=0s med=999.7µs max=80.18ms p(90)=1.88ms p(95)=2ms
25+
{ expected_response:true }...: avg=903.53µs min=0s med=999.7µs max=80.18ms p(90)=1.88ms p(95)=2ms
26+
http_req_failed................: 0.00% 0 out of 8333889
27+
http_req_receiving.............: avg=32.73µs min=0s med=0s max=74.14ms p(90)=0s p(95)=0s
28+
http_req_sending...............: avg=10.45µs min=0s med=0s max=60.82ms p(90)=0s p(95)=0s
29+
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
30+
http_req_waiting...............: avg=860.33µs min=0s med=999.5µs max=76.87ms p(90)=1.72ms p(95)=2ms
31+
http_reqs......................: 8333889 75762.281659/s
32+
iteration_duration.............: avg=1ms min=0s med=1ms max=84.13ms p(90)=1.99ms p(95)=2.01ms
33+
iterations.....................: 8333889 75762.281659/s
34+
vus............................: 1 min=1 max=100
35+
vus_max........................: 100 min=100 max=100
36+
37+
38+
running (1m50.0s), 000/100 VUs, 8333889 complete and 0 interrupted iterations
39+
default ✓ [======================================] 000/100 VUs 1m50s
40+
41+
42+
 k6  .\k6 run minimal_endpoint_basic.js
43+
44+
/\ Grafana /‾‾/
45+
/\ / \ |\ __ / /
46+
/ \/ \ | |/ / / ‾‾\
47+
/ \ | ( | (‾) |
48+
/ __________ \ |_|\_\ \_____/
49+
50+
execution: local
51+
script: minimal_endpoint_basic.js
52+
output: -
53+
54+
scenarios: (100.00%) 1 scenario, 100 max VUs, 2m20s max duration (incl. graceful stop):
55+
* default: Up to 100 looping VUs for 1m50s over 3 stages (gracefulRampDown: 30s, gracefulStop: 30s)
56+
57+
58+
✓ status was 200
59+
60+
checks.........................: 100.00% 8318368 out of 8318368
61+
data_received..................: 1.4 GB 13 MB/s
62+
data_sent......................: 890 MB 8.1 MB/s
63+
http_req_blocked...............: avg=3.26µs min=0s med=0s max=43.68ms p(90)=0s p(95)=0s
64+
http_req_connecting............: avg=8ns min=0s med=0s max=2.99ms p(90)=0s p(95)=0s
65+
✓ http_req_duration..............: avg=891µs min=0s med=999.5µs max=97.17ms p(90)=1.82ms p(95)=2ms
66+
{ expected_response:true }...: avg=891µs min=0s med=999.5µs max=97.17ms p(90)=1.82ms p(95)=2ms
67+
http_req_failed................: 0.00% 0 out of 8318368
68+
http_req_receiving.............: avg=32.59µs min=0s med=0s max=71.43ms p(90)=0s p(95)=0s
69+
http_req_sending...............: avg=10.52µs min=0s med=0s max=48.81ms p(90)=0s p(95)=0s
70+
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
71+
http_req_waiting...............: avg=847.88µs min=0s med=999.2µs max=97.17ms p(90)=1.69ms p(95)=2ms
72+
http_reqs......................: 8318368 75621.204645/s
73+
iteration_duration.............: avg=1ms min=0s med=1ms max=142.24ms p(90)=1.99ms p(95)=2.03ms
74+
iterations.....................: 8318368 75621.204645/s
75+
vus............................: 1 min=1 max=100
76+
vus_max........................: 100 min=100 max=100
77+
78+
79+
running (1m50.0s), 000/100 VUs, 8318368 complete and 0 interrupted iterations
80+
default ✓ [======================================] 000/100 VUs 1m50s
81+
82+
83+
 k6  .\k6 run webresult_endpoint_basic.js
84+
85+
/\ Grafana /‾‾/
86+
/\ / \ |\ __ / /
87+
/ \/ \ | |/ / / ‾‾\
88+
/ \ | ( | (‾) |
89+
/ __________ \ |_|\_\ \_____/
90+
91+
execution: local
92+
script: webresult_endpoint_basic.js
93+
output: -
94+
95+
scenarios: (100.00%) 1 scenario, 100 max VUs, 2m20s max duration (incl. graceful stop):
96+
* default: Up to 100 looping VUs for 1m50s over 3 stages (gracefulRampDown: 30s, gracefulStop: 30s)
97+
98+
99+
✓ status was 200
100+
101+
checks.........................: 100.00% 8190023 out of 8190023
102+
data_received..................: 1.4 GB 13 MB/s
103+
data_sent......................: 893 MB 8.1 MB/s
104+
http_req_blocked...............: avg=3.3µs min=0s med=0s max=40.88ms p(90)=0s p(95)=0s
105+
http_req_connecting............: avg=9ns min=0s med=0s max=2.99ms p(90)=0s p(95)=0s
106+
✓ http_req_duration..............: avg=920.69µs min=0s med=999.8µs max=77.18ms p(90)=1.96ms p(95)=2.01ms
107+
{ expected_response:true }...: avg=920.69µs min=0s med=999.8µs max=77.18ms p(90)=1.96ms p(95)=2.01ms
108+
http_req_failed................: 0.00% 0 out of 8190023
109+
http_req_receiving.............: avg=32.73µs min=0s med=0s max=57.97ms p(90)=0s p(95)=0s
110+
http_req_sending...............: avg=10.55µs min=0s med=0s max=46.61ms p(90)=0s p(95)=0s
111+
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
112+
http_req_waiting...............: avg=877.41µs min=0s med=999.6µs max=66.38ms p(90)=1.79ms p(95)=2ms
113+
http_reqs......................: 8190023 74454.706015/s
114+
iteration_duration.............: avg=1.02ms min=0s med=1ms max=89.37ms p(90)=1.99ms p(95)=2.02ms
115+
iterations.....................: 8190023 74454.706015/s
116+
vus............................: 1 min=1 max=100
117+
vus_max........................: 100 min=100 max=100
118+
119+
120+
running (1m50.0s), 000/100 VUs, 8190023 complete and 0 interrupted iterations
121+
default ✓ [======================================] 000/100 VUs 1m50s
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
 k6  .\k6 run minimal_api_inprocess.js
2+
3+
/\ Grafana /‾‾/
4+
/\ / \ |\ __ / /
5+
/ \/ \ | |/ / / ‾‾\
6+
/ \ | ( | (‾) |
7+
/ __________ \ |_|\_\ \_____/
8+
9+
execution: local
10+
script: minimal_api_inprocess.js
11+
output: -
12+
13+
scenarios: (100.00%) 1 scenario, 100 max VUs, 2m20s max duration (incl. graceful stop):
14+
* default: Up to 100 looping VUs for 1m50s over 3 stages (gracefulRampDown: 30s, gracefulStop: 30s)
15+
16+
17+
✓ status was 200
18+
19+
checks.........................: 100.00% 5854352 out of 5854352
20+
data_received..................: 1.1 GB 10 MB/s
21+
data_sent......................: 1.4 GB 13 MB/s
22+
http_req_blocked...............: avg=4.49µs min=0s med=0s max=74.36ms p(90)=0s p(95)=0s
23+
http_req_connecting............: avg=12ns min=0s med=0s max=2.04ms p(90)=0s p(95)=0s
24+
✓ http_req_duration..............: avg=1.26ms min=0s med=1.01ms max=131.02ms p(90)=2.05ms p(95)=2.52ms
25+
{ expected_response:true }...: avg=1.26ms min=0s med=1.01ms max=131.02ms p(90)=2.05ms p(95)=2.52ms
26+
http_req_failed................: 0.00% 0 out of 5854352
27+
http_req_receiving.............: avg=51.74µs min=0s med=0s max=123.76ms p(90)=0s p(95)=0s
28+
http_req_sending...............: avg=20.94µs min=0s med=0s max=77.71ms p(90)=0s p(95)=0s
29+
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
30+
http_req_waiting...............: avg=1.19ms min=0s med=1ms max=93.46ms p(90)=2.01ms p(95)=2.52ms
31+
http_reqs......................: 5854352 53221.183545/s
32+
iteration_duration.............: avg=1.43ms min=0s med=1.01ms max=132.03ms p(90)=2.28ms p(95)=2.85ms
33+
iterations.....................: 5854352 53221.183545/s
34+
vus............................: 1 min=1 max=100
35+
vus_max........................: 100 min=100 max=100
36+
37+
38+
running (1m50.0s), 000/100 VUs, 5854352 complete and 0 interrupted iterations
39+
default ✓ [======================================] 000/100 VUs 1m50s
40+
41+
42+
 k6  .\k6 run minimal_endpoint_inprocess.js
43+
44+
/\ Grafana /‾‾/
45+
/\ / \ |\ __ / /
46+
/ \/ \ | |/ / / ‾‾\
47+
/ \ | ( | (‾) |
48+
/ __________ \ |_|\_\ \_____/
49+
50+
execution: local
51+
script: minimal_endpoint_inprocess.js
52+
output: -
53+
54+
scenarios: (100.00%) 1 scenario, 100 max VUs, 2m20s max duration (incl. graceful stop):
55+
* default: Up to 100 looping VUs for 1m50s over 3 stages (gracefulRampDown: 30s, gracefulStop: 30s)
56+
57+
58+
✓ status was 200
59+
60+
checks.........................: 100.00% 5803262 out of 5803262
61+
data_received..................: 1.1 GB 9.9 MB/s
62+
data_sent......................: 1.4 GB 13 MB/s
63+
http_req_blocked...............: avg=4.32µs min=0s med=0s max=39.88ms p(90)=0s p(95)=0s
64+
http_req_connecting............: avg=14ns min=0s med=0s max=9.78ms p(90)=0s p(95)=0s
65+
✓ http_req_duration..............: avg=1.27ms min=0s med=1.01ms max=84.26ms p(90)=2.07ms p(95)=2.52ms
66+
{ expected_response:true }...: avg=1.27ms min=0s med=1.01ms max=84.26ms p(90)=2.07ms p(95)=2.52ms
67+
http_req_failed................: 0.00% 0 out of 5803262
68+
http_req_receiving.............: avg=47.14µs min=0s med=0s max=82.26ms p(90)=0s p(95)=0s
69+
http_req_sending...............: avg=19.79µs min=0s med=0s max=69.84ms p(90)=0s p(95)=0s
70+
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
71+
http_req_waiting...............: avg=1.21ms min=0s med=1.01ms max=83.26ms p(90)=2.03ms p(95)=2.52ms
72+
http_reqs......................: 5803262 52756.420044/s
73+
iteration_duration.............: avg=1.44ms min=0s med=1.02ms max=84.26ms p(90)=2.31ms p(95)=2.83ms
74+
iterations.....................: 5803262 52756.420044/s
75+
vus............................: 1 min=1 max=100
76+
vus_max........................: 100 min=100 max=100
77+
78+
79+
running (1m50.0s), 000/100 VUs, 5803262 complete and 0 interrupted iterations
80+
default ✓ [======================================] 000/100 VUs 1m50s
81+
82+
83+
 k6  .\k6 run webresult_endpoint_inprocess.js
84+
85+
/\ Grafana /‾‾/
86+
/\ / \ |\ __ / /
87+
/ \/ \ | |/ / / ‾‾\
88+
/ \ | ( | (‾) |
89+
/ __________ \ |_|\_\ \_____/
90+
91+
execution: local
92+
script: webresult_endpoint_inprocess.js
93+
output: -
94+
95+
scenarios: (100.00%) 1 scenario, 100 max VUs, 2m20s max duration (incl. graceful stop):
96+
* default: Up to 100 looping VUs for 1m50s over 3 stages (gracefulRampDown: 30s, gracefulStop: 30s)
97+
98+
99+
✓ status was 200
100+
101+
checks.........................: 100.00% 5767303 out of 5767303
102+
data_received..................: 1.1 GB 9.8 MB/s
103+
data_sent......................: 1.4 GB 13 MB/s
104+
http_req_blocked...............: avg=4.44µs min=0s med=0s max=53.62ms p(90)=0s p(95)=0s
105+
http_req_connecting............: avg=14ns min=0s med=0s max=6.82ms p(90)=0s p(95)=0s
106+
✓ http_req_duration..............: avg=1.29ms min=0s med=1.01ms max=91.78ms p(90)=2.1ms p(95)=2.53ms
107+
{ expected_response:true }...: avg=1.29ms min=0s med=1.01ms max=91.78ms p(90)=2.1ms p(95)=2.53ms
108+
http_req_failed................: 0.00% 0 out of 5767303
109+
http_req_receiving.............: avg=48.93µs min=0s med=0s max=82.25ms p(90)=0s p(95)=0s
110+
http_req_sending...............: avg=20.41µs min=0s med=0s max=66.9ms p(90)=0s p(95)=0s
111+
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
112+
http_req_waiting...............: avg=1.22ms min=0s med=1.01ms max=91.78ms p(90)=2.05ms p(95)=2.52ms
113+
http_reqs......................: 5767303 52429.944719/s
114+
iteration_duration.............: avg=1.45ms min=0s med=1.09ms max=108.91ms p(90)=2.34ms p(95)=2.82ms
115+
iterations.....................: 5767303 52429.944719/s
116+
vus............................: 1 min=1 max=100
117+
vus_max........................: 100 min=100 max=100
118+
119+
120+
running (1m50.0s), 000/100 VUs, 5767303 complete and 0 interrupted iterations
121+
default ✓ [======================================] 000/100 VUs 1m50s

src/ModEndpoints/DependencyInjectionExtensions.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ public static IServiceCollection AddModEndpointsFromAssembly(
2323
//WebResultEndpoint components
2424
services.TryAddKeyedSingleton<IResultToResponseMapper, DefaultResultToResponseMapper>(
2525
WebResultEndpointDefinitions.DefaultResultToResponseMapperName);
26+
services.TryAddKeyedSingleton<IPreferredSuccessStatusCodeCache, PreferredSuccessStatusCodeCacheForResult>(
27+
WebResultEndpointDefinitions.PreferredSuccessStatusCodeCacheNameForResult);
28+
services.TryAddKeyedSingleton<IPreferredSuccessStatusCodeCache, PreferredSuccessStatusCodeCacheForResultOfT>(
29+
WebResultEndpointDefinitions.PreferredSuccessStatusCodeCacheNameForResultOfT);
2630
services.TryAddScoped<ILocationStore, DefaultLocationStore>();
2731
services.TryAddSingleton<IResultToResponseMapProvider, DefaultResultToResponseMapProvider>();
2832

0 commit comments

Comments
 (0)