Skip to content

Commit 169ae19

Browse files
Copilotlahabana
andauthored
Implement x-failure-percentage header for fault injection control (#122)
## ✅ Implemented `x-failure-percentage` header for fault injection control This PR addresses issue #80 by implementing header-based fault injection, providing a better alternative to `MeshFaultInjection` for creating realistic and targeted demos. Fixes #80 Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: lahabana <[email protected]>
1 parent d291c2e commit 169ae19

File tree

2 files changed

+29
-2
lines changed

2 files changed

+29
-2
lines changed

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,5 +114,20 @@ To enforce response status code you need to set header `x-set-response-status-co
114114
curl localhost:5050/api/counter -XPOST -H "x-set-response-status-code: 503"
115115
```
116116

117+
### Simulating failures with fault injection
118+
119+
To simulate random failures you need to set header `x-failure-percentage` with a value between 0 and 100. A value of 0 (or missing header) means no failures, while 100 means always fail. Example:
120+
121+
```shell
122+
# 50% chance of failure
123+
curl localhost:5050/api/counter -XPOST -H "x-failure-percentage: 50"
124+
125+
# Always fail
126+
curl localhost:5050/api/version -H "x-failure-percentage: 100"
127+
128+
# No failures (same as not setting the header)
129+
curl localhost:5050/api/version -H "x-failure-percentage: 0"
130+
```
131+
117132
[kuma-url]: https://kuma.io/
118133
[kuma-logo]: https://kuma-public-assets.s3.amazonaws.com/kuma-logo-v2.png

app/internal/base/handler.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"github.com/kumahq/kuma-counter-demo/pkg/api"
77
"go.opentelemetry.io/otel/trace"
88
"log/slog"
9+
"math/rand"
910
"net/http"
1011
"strconv"
1112
"sync"
@@ -40,12 +41,23 @@ func (s *ServerImpl) writeResponse(w http.ResponseWriter, r *http.Request, origi
4041
if originalStatusCode/100 < 5 { // If the original status is 5xx ignore our override
4142
statusStr := r.Header.Get("x-set-response-status-code")
4243
if st, _ := strconv.Atoi(statusStr); st != 0 {
43-
originalStatusCode = st
44+
statusCode = st
45+
}
46+
// Handle fault injection via x-failure-percentage header
47+
if statusCode/100 < 4 { // Only inject faults for successful responses (2xx, 3xx)
48+
failurePercentageStr := r.Header.Get("x-failure-percentage")
49+
if failurePercentage, parseErr := strconv.Atoi(failurePercentageStr); parseErr == nil && failurePercentage > 0 {
50+
if failurePercentage >= 100 || rand.Intn(100) < failurePercentage {
51+
statusCode = http.StatusInternalServerError
52+
err = fmt.Errorf("simulated failure with %d%% chance", failurePercentage)
53+
}
54+
}
4455
}
4556
}
4657
w.Header().Set("Content-Type", "application/json; charset=utf-8")
4758
w.Header().Set("X-Demo-App-Version", s.version)
48-
w.WriteHeader(originalStatusCode)
59+
w.Header().Set("X-Original-Status-Code", strconv.Itoa(originalStatusCode))
60+
w.WriteHeader(statusCode)
4961
if err != nil {
5062
slog.ErrorContext(r.Context(), "failed request with error", "err", err, "status", statusCode, "response", response)
5163
} else {

0 commit comments

Comments
 (0)