aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFranck Cuny <franck@fcuny.net>2025-09-29 17:48:39 -0700
committerFranck Cuny <franck@fcuny.net>2025-09-29 17:48:39 -0700
commit070011b105dbf63369c5389115efccd079491aae (patch)
tree34f72cbd1c25436fc8285a468a3c390bc5399cc0
parentadd pr-analyzer (diff)
downloadx-070011b105dbf63369c5389115efccd079491aae.tar.gz
replacing my static website with a simple web app
Diffstat (limited to '')
-rw-r--r--app/fcuny-net/content/home.md8
-rw-r--r--app/fcuny-net/content/resume.md158
-rw-r--r--app/fcuny-net/main.go251
-rw-r--r--app/fcuny-net/static/main.css24
-rw-r--r--app/fcuny-net/static/resume.css189
-rw-r--r--app/fcuny-net/templates/home.html14
-rw-r--r--app/fcuny-net/templates/resume.html14
-rw-r--r--go.mod1
-rw-r--r--go.sum2
9 files changed, 661 insertions, 0 deletions
diff --git a/app/fcuny-net/content/home.md b/app/fcuny-net/content/home.md
new file mode 100644
index 0000000..edc90f8
--- /dev/null
+++ b/app/fcuny-net/content/home.md
@@ -0,0 +1,8 @@
+👋 I'm Franck, and this is my little corner on the web.
+
+- I'm a Technical Director at [Roblox](https://www.roblox.com)
+- Previously, I worked at [Twitter](https://twitter.com/TwitterEng) for close to 8 years. Before Twitter, I worked for different startups in S.F and Paris
+- I focus on Compute Infrastructure and Reliability
+- I live in Berkeley, and I'm married to the multi-talented artist [Felicia Martinez](https://www.feliciamartinez.com/about-1)
+
+The simplest way to contact me is via [email](mailto:hi@fcuny.net).
diff --git a/app/fcuny-net/content/resume.md b/app/fcuny-net/content/resume.md
new file mode 100644
index 0000000..eadcdb4
--- /dev/null
+++ b/app/fcuny-net/content/resume.md
@@ -0,0 +1,158 @@
+# Franck Cuny
+
+Technical Director Site Reliability Engineer
+
+Email: franck@fcuny.net | Phone: 415-617-5129
+
+Results-driven Site Reliability Engineering leader with extensive
+experience in architecting, scaling, and optimizing large-scale
+distributed systems. Proven track record of driving reliability
+improvements, fostering cross-functional collaboration, and mentoring
+engineering talent. Dedicated to building resilient infrastructures and
+cultivating a strong reliability culture.
+
+## Core Competencies:
+
+- Technical leadership and mentorship
+- Cross-team collaboration and communication
+- Large-scale distributed systems architecture
+- Reliability engineering and disaster recovery
+- Infrastructure optimization and cost reduction
+- Production readiness and failure testing methodologies
+
+## Career Focus:
+
+Seeking opportunities to lead transformative reliability initiatives,
+mentor the next generation of SREs, and drive architectural decisions
+that significantly enhance system resilience and performance at scale.
+
+# Experience
+
+## Roblox, San Mateo
+
+______________________________________________________________________
+
+Site Reliability Engineer Technical Director (IC7) August 2024 - to date
+Site Reliability Engineer Principal II (IC6) Feb 2022 - August 2024
+
+______________________________________________________________________
+
+As a Team Lead for the Site Reliability group, I define road-maps,
+milestones, and identify areas where SREs can partner with different
+teams to improve overall reliability of our infrastructure and services.
+Key projects and responsibilities include:
+
+- \*[Cell Architecture Implementation\*
+ ](https://corp.roblox.com/newsroom/2023/12/making-robloxs-infrastructure-efficient-resilient):
+ Led the SRE effort to transition from monolithic Compute clusters to
+ a Cell architecture, significantly enhancing Roblox's
+ infrastructure resilience and efficiency. Developed migration plans,
+ identified necessary automation, and drove production readiness for
+ this critical reliability improvement.
+
+- **Edge Infrastructure Migration**: Spearheaded the migration from
+ HAproxy to Envoy at the edge, aimed at reducing failure domains,
+ improving performance by streamlining the proxy chain, and enabling
+ user traffic steering to specific cells from the edge.
+
+- **Active/Passive Reliability Lead**: Orchestrated the failover
+ strategy across multiple teams, developing detailed action plans and
+ validation procedures. Conducted comprehensive tests to ensure plan
+ effectiveness. This work reduced the amount of time for a fail-over
+ from days to hours.
+
+- **Reliability Culture Champion**: Mentored engineers of various
+ levels (both SREs and SWEs), established a model for production
+ readiness, and popularized the practice of running failure exercises
+ for new large infrastructure projects.
+
+- **Technical Leadership**: Acted as tech lead on numerous projects,
+ demonstrating strong cross-team collaboration skills. Provided
+ technical guidance and mentorship to the SRE team, fostering a
+ culture of reliability and continuous improvement.
+
+Key strengths include driving complex infrastructure projects,
+mentoring, setting reliability standards, and facilitating effective
+cross-team collaboration.
+
+## Twitter, San Francisco
+
+______________________________________________________________________
+
+Site Reliability Engineer Senior Staff Engineer Jan 2018 - Jan 2022
+Site Reliability Engineer Staff Engineer Aug 2016 - Jan 2018
+Site Reliability Engineer Senior Engineer Aug 2014 - Jan 2016
+
+______________________________________________________________________
+
+### Key Achievements and Responsibilities:
+
+- **Large-Scale Infrastructure Management**: Led SRE efforts for one
+ of the world's largest compute clusters (Mesos), spanning hundred
+ of thousands of nodes across multiple data centers. Defined KPIs and
+ improved automation for managing a massive fleet of bare metal
+ machines.
+
+- **Kubernetes Adoption**: Spearheaded the initiative to adopt
+ Kubernetes for on-premise infrastructure, driving architectural
+ decisions and implementation strategies.
+
+- **Cost Optimization**: Designed and implemented strategies that
+ significantly improved hardware utilization, resulting in tens of
+ millions of dollars in savings on hardware costs.
+
+- **Tech Leadership**: Served as Tech Lead for a team of 6 SREs
+ supporting Compute infrastructure. Established critical team
+ processes including on-call rotations and postmortem procedures.
+
+- **Cloud and On-Premise Expertise**: Led multiple efforts related to
+ Kubernetes deployment and management, both in cloud environments and
+ on-premise infrastructure.
+
+- **Storage Systems Migration**: Successfully migrated all pub-sub
+ systems from bare-metal deployment to Aurora/Mesos, pioneering the
+ adoption of the Compute orchestration platform among storage teams.
+ This transition reduced operational overhead, decreased deployment
+ times, and enhanced overall system reliability.
+
+- **Network Infrastructure Improvement**: Advocated for and
+ implemented the adoption of 10Gb+ networking in data centers,
+ enabling significant scaling improvements for storage systems.
+
+- **Cross-Functional Leadership**: Served as the SRE Tech Lead for the
+ real time storage team, driving improvements in performance,
+ operations, and automation across storage systems.
+
+I consistently demonstrated the ability to lead complex technical
+initiatives, deliver impactful projects on-time, optimize large-scale
+systems, and drive cross-functional collaboration to achieve significant
+improvements in infrastructure reliability, efficiency, and
+cost-effectiveness.
+
+## Say Media, San Francisco
+
+______________________________________________________________________
+
+Software Engineer Senior Engineer Aug 2011 - Aug 2014
+
+______________________________________________________________________
+
+During my time at Say Media, I worked on two different teams. I started
+as a software engineer in the platform team building APIs then I then
+transitioned to the operation team to develop tooling in order to
+increase the effectiveness of the engineering organization.
+
+## Linkfluence, Paris
+
+______________________________________________________________________
+
+Software Engineer Senior SWE July 2007 - July 2011
+
+______________________________________________________________________
+
+I was one of the early engineers joining Linkfluence in 2007. I led the
+development of the company's crawler (web, feeds). I was responsible
+for defining the early architecture of the company, and designed the
+internal platforms (Service Oriented Architecture). I contributed to
+multiple open source projects on behalf of the company and represented
+the company at numerous open source conferences in Europe.
diff --git a/app/fcuny-net/main.go b/app/fcuny-net/main.go
new file mode 100644
index 0000000..8976964
--- /dev/null
+++ b/app/fcuny-net/main.go
@@ -0,0 +1,251 @@
+package main
+
+import (
+ "context"
+ "embed"
+ "fmt"
+ "html/template"
+ "io/fs"
+ "log"
+ "net/http"
+ "os"
+ "os/signal"
+ "path"
+ "runtime"
+ "syscall"
+ "time"
+
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/promauto"
+ "github.com/prometheus/client_golang/prometheus/promhttp"
+ "rsc.io/markdown"
+)
+
+//go:embed content/*
+var contentFiles embed.FS
+
+//go:embed static/*
+var staticFiles embed.FS
+
+//go:embed templates/*
+var templateFiles embed.FS
+
+const (
+ domain = "fcuny.net"
+ forgeDomain = "code.fcuny.net"
+ forgeUser = "fcuny"
+)
+
+type PageData struct {
+ Title string
+ Content template.HTML
+}
+
+var (
+ goGetReqs = promauto.NewCounterVec(prometheus.CounterOpts{
+ Name: "goget_requests_total",
+ Help: "go get requests processed, by repository name.",
+ }, []string{"name"})
+
+ staticReqs = promauto.NewCounterVec(prometheus.CounterOpts{
+ Name: "static_requests_total",
+ Help: "HTTP requests served from the FS.",
+ }, []string{"path"})
+
+ modules = []string{"x"}
+)
+
+func main() {
+ ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
+ defer cancel()
+
+ metricsMux := http.NewServeMux()
+ metricsMux.Handle("/metrics", promhttp.Handler())
+ metricsMux.Handle("/.info", info())
+
+ metricsServer := &http.Server{
+ Addr: ":9091",
+ Handler: metricsMux,
+ ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second,
+ }
+
+ go func() {
+ log.Println("Starting metrics server on :9091")
+ if err := metricsServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
+ log.Printf("Metrics server error: %v", err)
+ }
+ }()
+
+ s := &http.Server{
+ Addr: ":8070",
+ Handler: handler(),
+ ReadTimeout: 10 * time.Second,
+ WriteTimeout: 10 * time.Second,
+ IdleTimeout: 1 * time.Minute,
+ }
+
+ go func() {
+ log.Println("Starting main server on :8070")
+ if err := s.ListenAndServe(); err != nil && err != http.ErrServerClosed {
+ log.Printf("Main server error: %v", err)
+ }
+ }()
+
+ <-ctx.Done()
+ log.Println("Shutdown signal received, starting graceful shutdown...")
+
+ shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 30*time.Second)
+ defer shutdownCancel()
+
+ var shutdownErr error
+
+ log.Println("Shutting down main server...")
+ if err := s.Shutdown(shutdownCtx); err != nil {
+ log.Printf("Main server shutdown error: %v", err)
+ shutdownErr = err
+ }
+
+ log.Println("Shutting down metrics server...")
+ if err := metricsServer.Shutdown(shutdownCtx); err != nil {
+ log.Printf("Metrics server shutdown error: %v", err)
+ if shutdownErr == nil {
+ shutdownErr = err
+ }
+ }
+
+ if shutdownErr != nil {
+ log.Printf("Shutdown completed with errors")
+ os.Exit(1)
+ }
+
+ log.Println("Shutdown completed successfully")
+}
+
+func handler() http.Handler {
+ mux := http.NewServeMux()
+
+ staticFS, _ := fs.Sub(staticFiles, "static")
+ fileServer := http.FileServer(http.FS(staticFS))
+ mux.Handle("/static/", http.StripPrefix("/static/", fileServer))
+
+ mux.HandleFunc("/", homeHandler)
+ mux.HandleFunc("/resume", resumeHandler)
+
+ for _, name := range modules {
+ module := "/" + name
+ mux.Handle(
+ module+"/",
+ goImportHandler(module, "https://"+forgeDomain+"/"+forgeUser+"/"+name),
+ )
+ }
+
+ return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
+ if r.Method != http.MethodGet && r.Method != http.MethodHead {
+ status := http.StatusMethodNotAllowed
+ http.Error(rw, http.StatusText(status), status)
+ return
+ }
+ mux.ServeHTTP(rw, r)
+ })
+}
+
+func homeHandler(w http.ResponseWriter, r *http.Request) {
+ markdownContent, err := contentFiles.ReadFile("content/home.md")
+ if err != nil {
+ log.Printf("Error reading home markdown: %v", err)
+ http.Error(w, "Internal Server Error", http.StatusInternalServerError)
+ return
+ }
+
+ parser := markdown.Parser{}
+ doc := parser.Parse(string(markdownContent))
+
+ htmlContent := markdown.ToHTML(doc)
+
+ tmplContent, err := templateFiles.ReadFile("templates/home.html")
+ if err != nil {
+ log.Printf("Error reading template: %v", err)
+ http.Error(w, "Internal Server Error", http.StatusInternalServerError)
+ return
+ }
+
+ tmpl, err := template.New("layout").Parse(string(tmplContent))
+ if err != nil {
+ log.Printf("Error parsing template: %v", err)
+ http.Error(w, "Internal Server Error", http.StatusInternalServerError)
+ return
+ }
+
+ data := PageData{
+ Title: "Franck Cuny",
+ Content: template.HTML(htmlContent),
+ }
+
+ w.Header().Set("Content-Type", "text/html; charset=UTF-8")
+ if err := tmpl.Execute(w, data); err != nil {
+ log.Printf("Error executing template: %v", err)
+ }
+ staticReqs.WithLabelValues(path.Clean(r.URL.Path)).Inc()
+}
+
+func resumeHandler(w http.ResponseWriter, r *http.Request) {
+ markdownContent, err := contentFiles.ReadFile("content/resume.md")
+ if err != nil {
+ log.Printf("Error reading resume markdown: %v", err)
+ http.Error(w, "Internal Server Error", http.StatusInternalServerError)
+ return
+ }
+
+ parser := markdown.Parser{}
+ doc := parser.Parse(string(markdownContent))
+
+ htmlContent := markdown.ToHTML(doc)
+
+ tmplContent, err := templateFiles.ReadFile("templates/resume.html")
+ if err != nil {
+ log.Printf("Error reading template: %v", err)
+ http.Error(w, "Internal Server Error", http.StatusInternalServerError)
+ return
+ }
+
+ tmpl, err := template.New("layout").Parse(string(tmplContent))
+ if err != nil {
+ log.Printf("Error parsing template: %v", err)
+ http.Error(w, "Internal Server Error", http.StatusInternalServerError)
+ return
+ }
+
+ data := PageData{
+ Title: "Work Experience",
+ Content: template.HTML(htmlContent),
+ }
+
+ w.Header().Set("Content-Type", "text/html; charset=UTF-8")
+ if err := tmpl.Execute(w, data); err != nil {
+ log.Printf("Error executing template: %v", err)
+ }
+ staticReqs.WithLabelValues(path.Clean(r.URL.Path)).Inc()
+}
+
+func goImportHandler(module, repo string) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ goGetReqs.WithLabelValues(module).Inc()
+
+ if r.URL.Query().Get("go-get") == "1" {
+ w.Header().Set("Content-Type", "text/html; charset=UTF-8")
+ importPath := domain + module
+ if _, err := fmt.Fprintf(w, `<html><head><meta name="go-import" content="%s git %s"></head></html>`, importPath, repo); err != nil {
+ log.Printf("Error writing response: %v", err)
+ }
+ return
+ }
+
+ http.Redirect(w, r, repo, http.StatusFound)
+ })
+}
+
+func info() http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, "Go version: %s\n", runtime.Version())
+ })
+}
diff --git a/app/fcuny-net/static/main.css b/app/fcuny-net/static/main.css
new file mode 100644
index 0000000..12df426
--- /dev/null
+++ b/app/fcuny-net/static/main.css
@@ -0,0 +1,24 @@
+body {
+ width: auto;
+ max-width: 700px;
+ padding: 0 15px;
+ margin: 5rem auto;
+ font:
+ 1rem/2 -apple-system,
+ sans-serif;
+ background-color: white;
+ color: #242936;
+}
+p {
+ margin: 0 0 1em;
+}
+a {
+ color: inherit;
+ text-decoration: none;
+ border-bottom: 2px solid #007f9f;
+}
+ul {
+ display: inline-block;
+ text-align: left;
+ padding-left: 1em;
+}
diff --git a/app/fcuny-net/static/resume.css b/app/fcuny-net/static/resume.css
new file mode 100644
index 0000000..3fa95f0
--- /dev/null
+++ b/app/fcuny-net/static/resume.css
@@ -0,0 +1,189 @@
+/* Reset and base styles */
+* {
+ box-sizing: border-box;
+}
+
+body {
+ font-family: -apple-system, system-ui, sans-serif;
+ font-size: 16px;
+ line-height: 1.6;
+ color: #2c3e50;
+ margin: 0 auto;
+ padding: 2rem 1rem;
+ max-width: 50rem;
+ background: #fff;
+}
+
+/* Typography hierarchy */
+h1 {
+ font-size: 1.75rem;
+ font-weight: 700;
+ color: #2c3e50;
+ margin: 0 0 0.5rem 0;
+ line-height: 1.2;
+}
+
+h2 {
+ font-size: 1.25rem;
+ font-weight: 600;
+ color: #34495e;
+ margin: 2rem 0 1rem 0;
+ padding-bottom: 0.5rem;
+ border-bottom: 2px solid #e9ecef;
+}
+
+h3 {
+ font-size: 1.1rem;
+ font-weight: 600;
+ color: #495057;
+ margin: 1.5rem 0 0.75rem 0;
+}
+
+/* Header section */
+#title-block-header {
+ margin-bottom: 2rem;
+ padding-bottom: 1rem;
+ border-bottom: 3px solid #3498db;
+}
+
+/* Contact info and summary */
+.contact-info {
+ font-size: 0.95rem;
+ color: #6c757d;
+ margin-bottom: 1.5rem;
+}
+
+.contact-info a {
+ color: #3498db;
+ text-decoration: none;
+}
+
+.contact-info a:hover {
+ text-decoration: underline;
+}
+
+/* Lists */
+ul {
+ margin: 1rem 0;
+ padding-left: 1.5rem;
+}
+
+li {
+ margin-bottom: 0.5rem;
+}
+
+/* Job tables */
+table {
+ width: 100%;
+ margin: 1rem 0;
+ border-collapse: collapse;
+}
+
+td {
+ padding: 0.25rem 1rem 0.25rem 0;
+ font-family:
+ -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
+ font-size: 0.9rem;
+ vertical-align: top;
+}
+
+td:last-child {
+ text-align: right;
+ font-weight: 500;
+ color: #6c757d;
+}
+
+td:first-child {
+ font-weight: 600;
+ color: #495057;
+}
+
+td:nth-child(2) {
+ color: #6c757d;
+}
+
+/* Links */
+a {
+ color: #3498db;
+ text-decoration: none;
+ transition: color 0.2s ease;
+}
+
+a:hover {
+ color: #2980b9;
+ text-decoration: underline;
+}
+
+/* Strong text for emphasis */
+strong {
+ font-weight: 600;
+ color: #2c3e50;
+}
+
+/* Improved spacing for sections */
+#experience {
+ margin-top: 2rem;
+}
+
+/* Company sections */
+h2[id*="roblox"],
+h2[id*="twitter"],
+h2[id*="say-media"],
+h2[id*="linkfluence"] {
+ margin-top: 2.5rem;
+ font-size: 1.3rem;
+ color: #2c3e50;
+}
+
+/* Better paragraph spacing */
+p {
+ margin: 0.75rem 0;
+}
+
+/* Print styles */
+@media print {
+ body {
+ font-size: 12px;
+ line-height: 1.4;
+ padding: 0;
+ }
+
+ h1 {
+ font-size: 1.4rem;
+ }
+
+ h2 {
+ font-size: 1.1rem;
+ page-break-after: avoid;
+ }
+
+ table {
+ page-break-inside: avoid;
+ }
+
+ a {
+ color: inherit;
+ text-decoration: none;
+ }
+}
+
+/* Mobile responsiveness */
+@media (max-width: 600px) {
+ body {
+ padding: 1rem 0.75rem;
+ font-size: 15px;
+ }
+
+ h1 {
+ font-size: 1.5rem;
+ }
+
+ table {
+ font-size: 0.85rem;
+ }
+
+ td:last-child {
+ text-align: left;
+ font-size: 0.8rem;
+ }
+}
diff --git a/app/fcuny-net/templates/home.html b/app/fcuny-net/templates/home.html
new file mode 100644
index 0000000..d796401
--- /dev/null
+++ b/app/fcuny-net/templates/home.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>{{.Title}}</title>
+ <link rel="stylesheet" href="/static/main.css">
+</head>
+<body>
+ <main>
+ {{.Content}}
+ </main>
+</body>
+</html>
diff --git a/app/fcuny-net/templates/resume.html b/app/fcuny-net/templates/resume.html
new file mode 100644
index 0000000..86e854b
--- /dev/null
+++ b/app/fcuny-net/templates/resume.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>{{.Title}}</title>
+ <link rel="stylesheet" href="/static/resume.css">
+</head>
+<body>
+ <main>
+ {{.Content}}
+ </main>
+</body>
+</html>
diff --git a/go.mod b/go.mod
index 71f1388..1c6152c 100644
--- a/go.mod
+++ b/go.mod
@@ -21,4 +21,5 @@ require (
golang.org/x/crypto v0.41.0 // indirect
golang.org/x/sys v0.35.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
+ rsc.io/markdown v0.0.0-20241212154241-6bf72452917f // indirect
)
diff --git a/go.sum b/go.sum
index 812b501..78c6061 100644
--- a/go.sum
+++ b/go.sum
@@ -46,3 +46,5 @@ google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9x
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+rsc.io/markdown v0.0.0-20241212154241-6bf72452917f h1:zQHn9vNRGvg+k5NdSMZ5jdSQcuz7k5niNMO0f0XkwKc=
+rsc.io/markdown v0.0.0-20241212154241-6bf72452917f/go.mod h1:dTYI7HoCsVAs6SKPMgkC2TV2xRFJB9WqcVydnnZby2Y=