Last active
March 1, 2026 00:27
-
-
Save Malix-Labs/f0325731b45cbd6482b9f399bb3c0f91 to your computer and use it in GitHub Desktop.
Efrei 2026 Cloud Computing Lab 4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use flake |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| .direnv |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "flag" | |
| "fmt" | |
| "net/http" | |
| "os" | |
| "time" | |
| ) | |
| func main() { | |
| // Define the -port flag with a default of 8082 | |
| port := flag.String("port", "8082", "port to run the service on") | |
| flag.Parse() | |
| http.HandleFunc("/book", func(w http.ResponseWriter, r *http.Request) { | |
| event := r.URL.Query().Get("event") | |
| // Create a client with a strict 2-second timeout | |
| client := http.Client{ | |
| Timeout: 2 * time.Second, | |
| } | |
| // Synchronous critical dependency | |
| // Use the custom client instead of the default http.Get | |
| // Ask Event Service to decrement the slot | |
| resp, err := client.Get("http://localhost:8081/decrement?event=" + event) | |
| if err != nil || resp.StatusCode != http.StatusOK { | |
| http.Error(w, "Event sold out or unavailable", http.StatusConflict) | |
| return | |
| } | |
| if resp != nil { | |
| defer resp.Body.Close() | |
| } | |
| // Asynchronous non-critical dependency (Goroutine) | |
| go func(e string) { | |
| // We intentionally ignore errors here to prevent cascading failures | |
| _, _ = http.Get("http://localhost:8084/notify?event=" + e) | |
| }(event) | |
| // Include the port in the response to prove which instance handled it | |
| fmt.Fprintf(w, "Booking confirmed for %s (handled by port %s)\n", event, *port) | |
| }) | |
| fmt.Printf("Booking Service running on :%s\n", *port) | |
| if err := http.ListenAndServe(":"+*port, nil); err != nil { | |
| fmt.Println(err) | |
| os.Exit(1) | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "fmt" | |
| "net/http" | |
| "time" | |
| ) | |
| // We start with exactly 1 slot | |
| var events = map[string]int{"efrei-gala": 1} | |
| func main() { | |
| http.HandleFunc("/events", func(w http.ResponseWriter, r *http.Request) { | |
| for k, v := range events { | |
| fmt.Fprintf(w, "%s: %d slots\n", k, v) | |
| } | |
| }) | |
| http.HandleFunc("/decrement", func(w http.ResponseWriter, r *http.Request) { | |
| event := r.URL.Query().Get("event") | |
| slots := events[event] | |
| // 1. Validation check | |
| if slots <= 0 { | |
| http.Error(w, "Sold out", http.StatusConflict) | |
| return | |
| } | |
| // 2. The Vulnerability: We sleep while holding the validated state, | |
| // allowing other parallel requests to also pass the check above. | |
| time.Sleep(500 * time.Millisecond) | |
| // 3. State mutation | |
| events[event]-- | |
| w.WriteHeader(http.StatusOK) | |
| }) | |
| fmt.Println("Event Service running on :8081") | |
| http.ListenAndServe(":8081", nil) | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "nodes": { | |
| "flake-parts": { | |
| "inputs": { | |
| "nixpkgs-lib": "nixpkgs-lib" | |
| }, | |
| "locked": { | |
| "lastModified": 1769996383, | |
| "narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=", | |
| "owner": "hercules-ci", | |
| "repo": "flake-parts", | |
| "rev": "57928607ea566b5db3ad13af0e57e921e6b12381", | |
| "type": "github" | |
| }, | |
| "original": { | |
| "owner": "hercules-ci", | |
| "repo": "flake-parts", | |
| "type": "github" | |
| } | |
| }, | |
| "nix-systems": { | |
| "locked": { | |
| "lastModified": 1681028828, | |
| "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", | |
| "owner": "nix-systems", | |
| "repo": "default", | |
| "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", | |
| "type": "github" | |
| }, | |
| "original": { | |
| "owner": "nix-systems", | |
| "repo": "default", | |
| "type": "github" | |
| } | |
| }, | |
| "nixpkgs": { | |
| "locked": { | |
| "lastModified": 1771848320, | |
| "narHash": "sha256-2j5NAPU1sTVgnrj1FLxkBABP63q2DiRU2eIfEG56kPk=", | |
| "rev": "2fc6539b481e1d2569f25f8799236694180c0993", | |
| "type": "tarball", | |
| "url": "https://releases.nixos.org/nixos/unstable/nixos-26.05pre953160.2fc6539b481e/nixexprs.tar.xz" | |
| }, | |
| "original": { | |
| "type": "tarball", | |
| "url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz" | |
| } | |
| }, | |
| "nixpkgs-lib": { | |
| "locked": { | |
| "lastModified": 1769909678, | |
| "narHash": "sha256-cBEymOf4/o3FD5AZnzC3J9hLbiZ+QDT/KDuyHXVJOpM=", | |
| "owner": "nix-community", | |
| "repo": "nixpkgs.lib", | |
| "rev": "72716169fe93074c333e8d0173151350670b824c", | |
| "type": "github" | |
| }, | |
| "original": { | |
| "owner": "nix-community", | |
| "repo": "nixpkgs.lib", | |
| "type": "github" | |
| } | |
| }, | |
| "root": { | |
| "inputs": { | |
| "flake-parts": "flake-parts", | |
| "nix-systems": "nix-systems", | |
| "nixpkgs": "nixpkgs" | |
| } | |
| } | |
| }, | |
| "root": "root", | |
| "version": 7 | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| description = "Efrei 2026 Cloud Computing Lab 4"; | |
| inputs = { | |
| nixpkgs.url = "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz"; | |
| flake-parts.url = "github:hercules-ci/flake-parts"; | |
| nix-systems.url = "github:nix-systems/default"; | |
| }; | |
| outputs = | |
| inputs@{ | |
| self, | |
| nixpkgs, | |
| flake-parts, | |
| nix-systems, | |
| ... | |
| }: | |
| flake-parts.lib.mkFlake { inherit inputs; } { | |
| systems = import nix-systems; | |
| perSystem = | |
| { | |
| system, | |
| pkgs, | |
| ... | |
| }: | |
| { | |
| devShells.default = pkgs.mkShell { | |
| packages = with pkgs; [ | |
| go | |
| ]; | |
| }; | |
| }; | |
| }; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "fmt" | |
| "io" | |
| "net/http" | |
| "os" | |
| ) | |
| var bookingInstances = []string{"http://localhost:8082", "http://localhost:8083"} | |
| var requestCount = 0 | |
| // Helper to forward the request and return an error if the target is dead | |
| func proxy(w http.ResponseWriter, target string) error { | |
| resp, err := http.Get(target) | |
| if err != nil { | |
| return err | |
| } | |
| defer resp.Body.Close() | |
| // Copy the status code and body to the client | |
| w.WriteHeader(resp.StatusCode) | |
| _, err = io.Copy(w, resp.Body) | |
| return err | |
| } | |
| func main() { | |
| http.HandleFunc("/events", func(w http.ResponseWriter, r *http.Request) { | |
| if err := proxy(w, "http://localhost:8081/events"); err != nil { | |
| http.Error(w, "Event Service unreachable", http.StatusServiceUnavailable) | |
| } | |
| }) | |
| http.HandleFunc("/book", func(w http.ResponseWriter, r *http.Request) { | |
| // Round-robin selection | |
| primaryIdx := requestCount % len(bookingInstances) | |
| fallbackIdx := (requestCount + 1) % len(bookingInstances) | |
| requestCount++ | |
| target := bookingInstances[primaryIdx] + "/book?" + r.URL.RawQuery | |
| // Attempt primary instance | |
| if err := proxy(w, target); err != nil { | |
| fmt.Printf("Instance %s failed, falling back to %s\n", bookingInstances[primaryIdx], bookingInstances[fallbackIdx]) | |
| // Attempt fallback instance | |
| fallbackTarget := bookingInstances[fallbackIdx] + "/book?" + r.URL.RawQuery | |
| if err2 := proxy(w, fallbackTarget); err2 != nil { | |
| http.Error(w, "All Booking Services are unreachable", http.StatusServiceUnavailable) | |
| } | |
| } | |
| }) | |
| fmt.Println("API Gateway running on :8080") | |
| if err := http.ListenAndServe(":8080", nil); err != nil { | |
| fmt.Println(err) | |
| os.Exit(1) | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| module gist.github.com/Malix-Labs/f0325731b45cbd6482b9f399bb3c0f91 | |
| go 1.25.7 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "fmt" | |
| "net/http" | |
| "time" | |
| ) | |
| // In-memory state. No mutexes to intentionally allow logical race conditions later. | |
| var events = map[string]int{"efrei-gala": 2} | |
| var bookings = 0 | |
| func eventsHandler(w http.ResponseWriter, r *http.Request) { | |
| for k, v := range events { | |
| fmt.Fprintf(w, "%s: %d slots\n", k, v) | |
| } | |
| } | |
| func bookHandler(w http.ResponseWriter, r *http.Request) { | |
| event := r.URL.Query().Get("event") | |
| slots, exists := events[event] | |
| if !exists || slots <= 0 { | |
| http.Error(w, "sold out or not found", http.StatusBadRequest) | |
| return | |
| } | |
| // Artificial delay to widen the race condition window for Task 8 | |
| time.Sleep(50 * time.Millisecond) | |
| events[event] = slots - 1 | |
| bookings++ | |
| fmt.Fprintf(w, "booked %s. Total bookings: %d\n", event, bookings) | |
| } | |
| func main() { | |
| http.HandleFunc("/events", eventsHandler) | |
| http.HandleFunc("/book", bookHandler) | |
| fmt.Println("Monolith running on :8080") | |
| http.ListenAndServe(":8080", nil) | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "fmt" | |
| "net/http" | |
| "os" | |
| ) | |
| func main() { | |
| http.HandleFunc("/notify", func(w http.ResponseWriter, r *http.Request) { | |
| event := r.URL.Query().Get("event") | |
| fmt.Printf("Notification triggered: Confirmation email sent for %s\n", event) | |
| w.WriteHeader(http.StatusOK) | |
| }) | |
| fmt.Println("Notification Service running on :8084") | |
| if err := http.ListenAndServe(":8084", nil); err != nil { | |
| fmt.Println(err) | |
| os.Exit(1) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment