Skip to content

Commit cf79e12

Browse files
committed
Initial commit.
0 parents  commit cf79e12

16 files changed

+572
-0
lines changed

.env

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
PORT=8080

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.swp

Dockerfile

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
FROM golang:1.13-alpine as build
2+
RUN apk add git
3+
RUN go get github.com/securego/gosec/cmd/gosec/...
4+
RUN go get github.com/githubnemo/CompileDaemon
5+
ADD . /app
6+
WORKDIR /app
7+
RUN go build -o code-challenge-golang .
8+
9+
FROM alpine as app
10+
COPY --from=build /app/code-challenge-golang /app/
11+
WORKDIR /app
12+
CMD ["./code-challenge-golang"]

README.md

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Brandfolder Code-Challenge-Golang
2+
3+
### Requirements
4+
- Docker Compose
5+
6+
### How to get started
7+
Given the need to pull some docker containers, it'd be beneficial to start that process:
8+
```
9+
docker-compose up
10+
```
11+
12+
13+
This repository represents an application that accepts a list of files via a
14+
```
15+
POST /download
16+
[
17+
{
18+
"filename": "fname.png",
19+
"url": "https://url.com/to/file.png",
20+
"gcsUrl": "gs://bucketname/path/to/file.png" # Optional
21+
}.
22+
...
23+
]
24+
```
25+
26+
The repo in it's entirely contains a few components (loadgen-server, main.go, dependency-server). Here is a Flow Diagram that depicts the lifecycle of the repo.
27+
28+
![Flow Diagram](https://www.websequencediagrams.com/cgi-bin/cdraw?lz=dGl0bGUgY29kZS1jaGFsbGVuZ2UtZ29sYW5nIGFwcGxpY2F0aW9uIGZsb3cgZGlhZ3JhbQoKcGFydGljaXBhbnQgbG9hZGdlbi1zZXJ2ZXIADg1uZ2lueAAgDQBUFQATD250ZW50CgoASg4tPisAgRAVOiByZXF1ZXN0IGxpc3Qgb2YgZmlsZXMKbG9vcAAGBQogAIFIFgBMBQBmBTogZmV0Y2gAJAoAfAUtLT4tAFsXc3RyZWFtAFgGZW5kCgBKFi0-LQCCDQ4AMAl6aXA&s=default)
29+
30+
31+
The responsibility of the application under question is contained within the `main.go` application. It's responsibility is to decode the request (list of files), compile them into a zip, and stream them to the client.
32+
33+
This service has a mixture of end-users, and it's importance and footprint has grown. We're starting to hear that there are errors in the functionality delivered to end-users, and would like help debugging and correcting some of the errors.
34+
35+
In the midst of this work, please make an effort to make logical improvements to the service and up-level our practices. Do your best to describe your intentions and coach us as team members on how we should think about making changes.
36+
37+
### Goal of this exercise
38+
1. Help us identify the effectiveness/failures of this service
39+
1. Suggestion of how this could be quantified/monitored
40+
1. Make changes to reduce the failure rate
41+
1. Suggest and possibly implement structural changes to the code for better maintainability
42+
43+
Open main.go for assessing code footpring and editing
44+
45+
### Commands to help
46+
```
47+
docker-compose logs -f nginx
48+
docker-compose logs -f code-challenge-golang
49+
```

code-challenge-golang

14.9 MB
Binary file not shown.

dependent-server/Dockerfile

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
FROM golang:1.13-alpine as build
2+
RUN apk add git
3+
RUN go get github.com/githubnemo/CompileDaemon
4+
ADD . /app
5+
WORKDIR /app
6+
RUN go build -o dependent-server .
7+
8+
FROM alpine as app
9+
COPY --from=build /app/dependent-server /app/
10+
CMD ["/app/dependent-server"]

dependent-server/dependent-server

7.12 MB
Binary file not shown.

dependent-server/main.go

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package main
2+
3+
// http server that logs requests and allows clients to define response duration and returned status code.
4+
//
5+
// Examples:
6+
// # return a response after 10 minutes with a 500 status code
7+
// curl <host>/?duration=10m&statusCode=500
8+
//
9+
// # return a response after 20 seconds with a 201 status code
10+
// curl <host>/?duration=10m&statusCode=500
11+
//
12+
// # return a response immediately with a 200 status code (defaults)
13+
// curl <host>/
14+
15+
import (
16+
"fmt"
17+
"io/ioutil"
18+
"log"
19+
"net/http"
20+
"os"
21+
"strconv"
22+
"time"
23+
)
24+
25+
func handler(w http.ResponseWriter, r *http.Request) {
26+
//log.Print("echo server received a request")
27+
28+
query := r.URL.Query()
29+
statusCode := query.Get("statusCode")
30+
duration := query.Get("duration")
31+
32+
body, err := ioutil.ReadAll(r.Body)
33+
if err != nil {
34+
//log.Printf("error reading body: %v", err)
35+
return
36+
}
37+
38+
if len(body) > 0 {
39+
//log.Printf("body received: %v", string(body))
40+
}
41+
42+
if duration != "" {
43+
d, err := time.ParseDuration(duration)
44+
if err != nil {
45+
msg := fmt.Sprintf("invalid duration: %v", duration)
46+
//log.Print(msg)
47+
w.WriteHeader(http.StatusBadRequest)
48+
_, _ = w.Write([]byte(msg))
49+
return
50+
}
51+
//log.Printf("sleeping requested duration: %v", d)
52+
time.Sleep(d)
53+
}
54+
55+
if statusCode != "" {
56+
s, err := strconv.Atoi(statusCode)
57+
if err != nil {
58+
msg := fmt.Sprintf("invalid statusCode: %v", statusCode)
59+
//log.Print(msg)
60+
w.WriteHeader(http.StatusBadRequest)
61+
_, _ = w.Write([]byte(msg))
62+
return
63+
}
64+
w.WriteHeader(s)
65+
if s == 200 {
66+
log.Println("printing image")
67+
w.Write([]byte{137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 1, 0, 0, 0, 1, 8, 2, 0, 0, 0, 144, 119, 83, 222, 0, 0, 0, 12, 73, 68, 65, 84, 8, 215, 99, 216, 122, 225, 2, 0, 4, 147, 2, 86, 234, 93, 183, 214, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130})
68+
}
69+
return
70+
}
71+
w.WriteHeader(http.StatusOK)
72+
}
73+
74+
func main() {
75+
//log.Print("echo server started")
76+
77+
http.HandleFunc("/", handler)
78+
79+
port := os.Getenv("PORT")
80+
if port == "" {
81+
port = "8080"
82+
}
83+
84+
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), nil))
85+
}

docker-compose.yml

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
version: "3.7"
2+
services:
3+
code-challenge-golang:
4+
build:
5+
target: build
6+
context: .
7+
env_file:
8+
- .env
9+
volumes:
10+
- .:/app
11+
ports:
12+
- 8080:8080
13+
command:
14+
CompileDaemon -directory="/app" -build="go build -o code-challenge-golang ." -command="/app/code-challenge-golang"
15+
networks:
16+
- internal-network
17+
- dependent-network
18+
depends_on:
19+
- dependent-server
20+
nginx:
21+
image: nginx:latest
22+
volumes:
23+
- ./nginx.conf:/etc/nginx/nginx.conf
24+
ports:
25+
- 80:80
26+
networks:
27+
- internal-network
28+
depends_on:
29+
- code-challenge-golang
30+
dependent-server:
31+
build:
32+
context: dependent-server
33+
target: build
34+
environment:
35+
- PORT=8090
36+
ports:
37+
- 8090:8090
38+
volumes:
39+
- ./dependent-server:/app
40+
command:
41+
CompileDaemon -directory="/app" -build="go build -o dependent-server ." -command="/app/dependent-server"
42+
networks:
43+
- dependent-network
44+
loadgen-server:
45+
build:
46+
context: loadgen-server
47+
volumes:
48+
- ./loadgen-server:/app
49+
networks:
50+
- internal-network
51+
command:
52+
python make_requests.py
53+
54+
networks:
55+
internal-network:
56+
dependent-network:

go.mod

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module github.com/brandfolder/code-challenge-golang
2+
3+
go 1.13
4+
5+
require cloud.google.com/go/storage v1.5.0

0 commit comments

Comments
 (0)