Skip to content

Commit b61c818

Browse files
committed
feat: init
1 parent de6531f commit b61c818

File tree

21 files changed

+755
-0
lines changed

21 files changed

+755
-0
lines changed

.github/workflows/build.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Workflow for building the demo service
2+
3+
name: Build Service
4+
5+
# Controls when the action will run.
6+
on:
7+
# Triggers the workflow on push or pull request events but only for the main branch
8+
pull_request:
9+
branches: [ main ]
10+
11+
# Allows you to run this workflow manually from the Actions tab
12+
workflow_dispatch:
13+
14+
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
15+
jobs:
16+
# This workflow contains a single job called "build"
17+
build:
18+
# The type of runner that the job will run on
19+
runs-on: ubuntu-latest
20+
21+
# Steps represent a sequence of tasks that will be executed as part of the job
22+
steps:
23+
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
24+
- uses: actions/checkout@v4
25+
26+
- name: Set up Go
27+
id: go
28+
uses: actions/setup-go@v5
29+
with:
30+
go-version: 1.22
31+
cache: false
32+
33+
# Fetches all necessary go packages and builds the project
34+
- name: Build
35+
run: |
36+
go build -o anomaly-simulation-service
37+
38+
39+

.github/workflows/release.yml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Create and publish an OCI image
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
env:
9+
REGISTRY: ghcr.io
10+
IMAGE_NAME: ${{ github.repository }}
11+
12+
jobs:
13+
build-and-push-image:
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- name: Determine next version and push tag
20+
id: semantic-release
21+
uses: codfish/semantic-release-action@v3
22+
with:
23+
tag-format: 'v${version}'
24+
branches: |
25+
[ 'main' ]
26+
plugins: |
27+
['@semantic-release/commit-analyzer', '@semantic-release/release-notes-generator', '@semantic-release/github']
28+
env:
29+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
30+
31+
- name: Log in to the container registry (GitHub packages)
32+
if: steps.semantic-release.outputs.new-release-published == 'true'
33+
uses: docker/login-action@v3
34+
with:
35+
registry: ${{ env.REGISTRY }}
36+
username: ${{ github.actor }}
37+
password: ${{ secrets.GITHUB_TOKEN }}
38+
39+
- name: Extract metadata (tags, labels) for Docker
40+
if: steps.semantic-release.outputs.new-release-published == 'true'
41+
id: meta
42+
uses: docker/metadata-action@v5
43+
with:
44+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
45+
tags: |
46+
# Set version tag based on semantic release output
47+
type=semver,pattern=v{{version}},value=${{ steps.semantic-release.outputs.release-version }}
48+
# Set latest tag
49+
type=raw,value=latest
50+
51+
- name: Build and push Docker image
52+
if: steps.semantic-release.outputs.new-release-published == 'true'
53+
id: push
54+
uses: docker/build-push-action@v6
55+
with:
56+
context: .
57+
push: true
58+
tags: ${{ steps.meta.outputs.tags }}
59+
labels: ${{ steps.meta.outputs.labels }}

.gitignore

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Binaries for programs and plugins
2+
*.exe
3+
*.exe~
4+
*.dll
5+
*.so
6+
*.dylib
7+
8+
anomaly-simulation-service
9+
10+
# Test binary, build with `go test -c`
11+
*.test
12+
13+
# Output of the go coverage tool, specifically when used with LiteIDE
14+
*.out
15+
16+
# IntelliJ Idea
17+
.idea

Dockerfile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# syntax=docker/dockerfile:1
2+
FROM golang:1.22
3+
4+
WORKDIR /app
5+
6+
COPY go.mod *.go ./
7+
RUN CGO_ENABLED=0 GOOS=linux go build -o /anomaly-simulation-service
8+
9+
EXPOSE 8080
10+
11+
CMD ["/anomaly-simulation-service"]

README.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Generic demo service
2+
3+
Purpose of this service is to simulate specific anomaly situations, such as:
4+
5+
- Slowdowns
6+
- Failures
7+
- Increase in resource consumption
8+
- Process crashes
9+
- Calls to one or more other services
10+
11+
Therefore, this generic service can be used to build all kinds of variable demo
12+
situations with either flat or deep call trees.
13+
14+
The service listenes on following HTTP resource pathes:
15+
- GET '/' normal page return
16+
- POST '/config' service receives anomaly config as a HTTP POST message with a JSON config payload that is defined below.
17+
18+
Thanks to [Wolfgang Beer](https://github.com/wolfgangB33r) for the initial implementation of this service.
19+
20+
## Usage
21+
22+
Start service by specifying a listening port:
23+
`./service.exe 8090`
24+
Start the service multiple times and let the services call each other
25+
`./service.exe 8090`
26+
`./service.exe 8091`
27+
28+
## Dynamically reconfigure the service
29+
30+
Push a http POST request to /config on your started service.
31+
32+
## Config JSON body
33+
34+
Count always represents the number of service requests that suffer from that anomaly, e.g.: a count of 5 means the next 5 service requests are affected.
35+
A crash anomaly kills the service process with the given exit code. The resource anomaly allocates a matrix of 100x100 elements multiplied by the given severity.
36+
Callees let you specify the callees this service calls with each service request. Specifying callees allows you to build dynamic multi-level service call trees.
37+
In case the attribute 'Balanced' is set to 'true', the callees are equally iterated with each request.
38+
39+
```json
40+
{
41+
"ErrorConfig": {
42+
"ResponseCode": 500,
43+
"Count": 5
44+
},
45+
"SlowdownConfig": {
46+
"SlowdownMillis": 500,
47+
"Count": 1
48+
},
49+
"CrashConfig": {
50+
"Code": 3
51+
},
52+
"ResourceConfig": {
53+
"Severity": 5,
54+
"Count": 2
55+
},
56+
"Callees": [
57+
{
58+
"Adr": "http://www.example.com",
59+
"Count": 10
60+
},
61+
{
62+
"Adr": "http://www.orf.at",
63+
"Count": 3
64+
},
65+
{
66+
"Adr": "http://localhost:8090",
67+
"Count": 3
68+
}
69+
],
70+
"Balanced": true
71+
}
72+
```
73+
74+
## Example topology
75+
76+
The `example1/start.sh` shell script copies the generic demo service into 6 individual services. Starts those 6 services on the same machine on 6 different ports and configures them to call them each other in the topology shown by Dynatrace below:
77+
78+
![](examples/example1/example1.png)
79+
80+
## Balanced example
81+
82+
The `balancer/start.sh` shell script copies the generic demo service into 6 individual services. Starts those 6 services on the same machine on 6 different ports and configures them to form a balancer and worker pool topology, as it is shown by Dynatrace below:
83+
84+
![](examples/balancer/balancer.png)
85+
86+
87+

examples/balancer/balancer.png

10.8 KB
Loading

examples/balancer/start.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
pkill balancer
2+
pkill worker
3+
4+
sleep 5
5+
6+
cp ../../anomaly-simulation-service balancer
7+
cp ../../anomaly-simulation-service worker
8+
9+
./balancer 9000&
10+
DT_IGNOREDYNAMICPORT=true DT_NODE_ID=1 ./worker 9100&
11+
DT_IGNOREDYNAMICPORT=true DT_NODE_ID=2 ./worker 9200&
12+
DT_IGNOREDYNAMICPORT=true DT_NODE_ID=3 ./worker 9300&
13+
DT_IGNOREDYNAMICPORT=true DT_NODE_ID=4 ./worker 9400&
14+
DT_IGNOREDYNAMICPORT=true DT_NODE_ID=5 ./worker 9500&
15+
16+
sleep 5
17+
18+
curl -i -X POST \
19+
-H "Content-Type:application/json" \
20+
-d \
21+
'{
22+
"Callees" : [
23+
{ "Adr" : "http://localhost:9100", "Count" : 1 },
24+
{ "Adr" : "http://localhost:9200", "Count" : 1 },
25+
{ "Adr" : "http://localhost:9300", "Count" : 1 },
26+
{ "Adr" : "http://localhost:9400", "Count" : 1 },
27+
{ "Adr" : "http://localhost:9500", "Count" : 1 }
28+
],
29+
"Balanced" : true
30+
}' \
31+
'http://localhost:9000/config'
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# first, configure the balancer to only send to 2 workers instead of previously 5
2+
3+
curl -i -X POST \
4+
-H "Content-Type:application/json" \
5+
-d \
6+
'{
7+
"Callees" : [
8+
{ "Adr" : "http://localhost:9400", "Count" : 3 },
9+
{ "Adr" : "http://localhost:9500", "Count" : 3 }
10+
],
11+
"Balanced" : true
12+
}' \
13+
'http://localhost:9000/config'
14+
15+
# then, slowdown the remaining 2 workers because of the load shift
16+
17+
sleep 80
18+
19+
curl -i -X POST \
20+
-H "Content-Type:application/json" \
21+
-d \
22+
'{
23+
"SlowdownConfig" : {
24+
"SlowdownMillis" : 500,
25+
"Count" : 3000
26+
},
27+
"Callees" : [
28+
]
29+
}' \
30+
'http://localhost:9400/config'
31+
32+
curl -i -X POST \
33+
-H "Content-Type:application/json" \
34+
-d \
35+
'{
36+
"SlowdownConfig" : {
37+
"SlowdownMillis" : 500,
38+
"Count" : 3000
39+
},
40+
"Callees" : [
41+
]
42+
}' \
43+
'http://localhost:9500/config'

examples/example1/example1.png

46.7 KB
Loading

examples/example1/start.sh

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
pkill customerAPI
2+
pkill sideService
3+
pkill calcService
4+
pkill restService
5+
pkill recomService
6+
pkill modelService
7+
8+
sleep 5
9+
10+
cp ../../anomaly-simulation-service customerAPI
11+
cp ../../anomaly-simulation-service sideService
12+
cp ../../anomaly-simulation-service calcService
13+
cp ../../anomaly-simulation-service restService
14+
cp ../../anomaly-simulation-service recomService
15+
cp ../../anomaly-simulation-service modelService
16+
17+
./customerAPI 8080 > customerapi.log 2>&1 &
18+
./sideService 8081 > sideservice.log 2>&1 &
19+
./calcService 8082 > calcservice.log 2>&1 &
20+
./restService 8083 > restservice.log 2>&1 &
21+
./recomService 8084 > recomservice.log 2>&1 &
22+
./modelService 8085 > modelservice.log 2>&1 &
23+
24+
sleep 5
25+
26+
curl -i -X POST \
27+
-H "Content-Type:application/json" \
28+
-d \
29+
'{
30+
"Callees" : [
31+
{ "Adr" : "http://localhost:8081", "Count" : 2 },
32+
{ "Adr" : "http://localhost:8082", "Count" : 3 },
33+
{ "Adr" : "http://www.example.com", "Count" : 1 }
34+
]
35+
}' \
36+
'http://localhost:8080/config'
37+
38+
curl -i -X POST \
39+
-H "Content-Type:application/json" \
40+
-d \
41+
'{
42+
"Callees" : [
43+
{ "Adr" : "http://localhost:8083", "Count" : 2 },
44+
{ "Adr" : "http://localhost:8084", "Count" : 2 },
45+
{ "Adr" : "http://www.example.com", "Count" : 1 }
46+
]
47+
}' \
48+
'http://localhost:8081/config'
49+
50+
curl -i -X POST \
51+
-H "Content-Type:application/json" \
52+
-d \
53+
'{
54+
"Callees" : [
55+
{ "Adr" : "http://localhost:8085", "Count" : 2 },
56+
{ "Adr" : "http://www.example.com", "Count" : 1 }
57+
]
58+
}' \
59+
'http://localhost:8084/config'

0 commit comments

Comments
 (0)