Skip to content
Closed
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
d8dc71f
WIP sandbox event endpoint boilerplate
0div Jun 16, 2025
d7363e9
fix merge conflict with main
0div Jun 16, 2025
587f92e
WIP working sandbox event endpoint boilerplate
0div Jun 16, 2025
61c8fe9
renaming and changes in file structure
0div Jun 17, 2025
67abc7c
fix merge conflict with main
0div Jun 19, 2025
b39dd56
WIP abstract event server in its own sandbox submodule; add some head…
0div Jun 19, 2025
4aefc4a
Merge branch 'main' of https://github.com/e2b-dev/infra into create-i…
0div Jun 20, 2025
78bfc5a
cosmetic edits
0div Jun 20, 2025
599531e
Merge branch 'main' of https://github.com/e2b-dev/infra into create-i…
0div Jun 20, 2025
6f1aa77
address gofumpt errors
0div Jun 20, 2025
c47a330
Merge branch 'main' of https://github.com/e2b-dev/infra into create-i…
0div Jun 23, 2025
087c421
store events in redis via a catchall endpoint
0div Jun 23, 2025
19a18a7
create event store interface
0div Jun 24, 2025
d8ca2e6
fix event store
0div Jun 24, 2025
5aa2b58
go mod tidy & go work sync
0div Jun 24, 2025
59ea4ad
fix merge conflict with main
0div Jun 24, 2025
be5c2ad
go mod tidy api
0div Jun 25, 2025
eb5ca83
use sorted set for events time-series
0div Jun 25, 2025
3179789
go-lint problematic file
0div Jun 25, 2025
30e2cd8
add redis to start-services action
0div Jun 25, 2025
881fbb0
add redis_url to template-manager iac
0div Jun 25, 2025
89eb6fb
remove proto from redis url in github actions
0div Jun 25, 2025
fdc5cdb
update openapi spec for sandbox events endpoint
0div Jun 26, 2025
333bb17
fix merge conflict with main
0div Jul 2, 2025
e2e6e2c
Merge branch 'main' of https://github.com/e2b-dev/infra into create-i…
0div Jul 3, 2025
6abcc04
Merge branch 'main' of https://github.com/e2b-dev/infra into create-i…
0div Jul 7, 2025
fd4e9a1
Merge branch 'main' of https://github.com/e2b-dev/infra into create-i…
0div Jul 8, 2025
b4bb3f6
track Sandbox IPs via store during key Sandbox lifecycle steps relati…
0div Jul 8, 2025
7535b6e
remove sandbox id middleware
0div Jul 8, 2025
d25a9f3
use public ip address for sandbox event routing that is not meant to …
0div Jul 10, 2025
60de6a2
fix merge conflict with main
0div Jul 10, 2025
4309142
golint
0div Jul 11, 2025
78ffeba
introduce internal const.go to orchestrator package
0div Jul 11, 2025
0b69432
Merge branch 'main' of https://github.com/e2b-dev/infra into create-i…
0div Jul 11, 2025
6d666e6
Merge branch 'main' of https://github.com/e2b-dev/infra into create-i…
0div Jul 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/nomad/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ locals {
otel_collector_grpc_endpoint = "localhost:${var.otel_collector_grpc_port}"
allow_sandbox_internet = var.allow_sandbox_internet
launch_darkly_api_key = trimspace(data.google_secret_manager_secret_version.launch_darkly_api_key.secret_data)
redis_url = data.google_secret_manager_secret_version.redis_url.secret_data != "redis.service.consul" ? "${data.google_secret_manager_secret_version.redis_url.secret_data}:${var.redis_port.port}" : "redis.service.consul:${var.redis_port.port}"
}

orchestrator_job_check = templatefile("${path.module}/orchestrator.hcl", merge(
Expand Down Expand Up @@ -651,4 +652,4 @@ resource "nomad_job" "clickhouse_migrator" {
clickhouse_password = random_password.clickhouse_password.result
clickhouse_port = var.clickhouse_server_port.port
})
}
}
1 change: 1 addition & 0 deletions packages/nomad/orchestrator.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ EOT
TEMPLATE_BUCKET_NAME = "${template_bucket_name}"
OTEL_COLLECTOR_GRPC_ENDPOINT = "${otel_collector_grpc_endpoint}"
ALLOW_SANDBOX_INTERNET = "${allow_sandbox_internet}"
REDIS_URL = "${redis_url}"

%{ if launch_darkly_api_key != "" }
LAUNCH_DARKLY_API_KEY = "${launch_darkly_api_key}"
Expand Down
5 changes: 4 additions & 1 deletion packages/orchestrator/cmd/build-template/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ import (
"github.com/e2b-dev/infra/packages/shared/pkg/storage"
)

const proxyPort = 5007
const (
proxyPort = 5007
sbxEventServerPort = 5010
)

func main() {
ctx, cancel := context.WithCancel(context.Background())
Expand Down
2 changes: 2 additions & 0 deletions packages/orchestrator/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ require (
github.com/containernetworking/cni v1.2.3 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dchest/uniuri v1.2.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/cli v28.1.1+incompatible // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
Expand Down Expand Up @@ -169,6 +170,7 @@ require (
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/redis/go-redis/v9 v9.10.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect
github.com/ulikunitz/xz v0.5.12 // indirect
Expand Down
4 changes: 4 additions & 0 deletions packages/orchestrator/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@ github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4
github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
Expand Down Expand Up @@ -937,6 +939,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/redis/go-redis/v9 v9.10.0 h1:FxwK3eV8p/CQa0Ch276C7u2d0eNC9kCmAYQ7mCXCzVs=
github.com/redis/go-redis/v9 v9.10.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
Expand Down
104 changes: 104 additions & 0 deletions packages/orchestrator/internal/sandbox/event/handlers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package event

import (
"encoding/json"
"io"
"net/http"

"github.com/redis/go-redis/v9"
)

type EventHandler interface {
Path() string
HandlerFunc(w http.ResponseWriter, r *http.Request)
}

type EventData struct {
Path string `json:"path"`
Body map[string]any `json:"body"`
}

type MetricsHandler struct{}

func (h *MetricsHandler) Path() string {
return "/metrics"
}

func (h *MetricsHandler) HandlerFunc(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
_, err := w.Write([]byte(`{"event_ack":true,"path":"/metrics"}`))
if err != nil {
http.Error(w, "Failed to write response", http.StatusInternalServerError)
return
}
}

// This handler is used to store event data for all paths that are not registered in the event server.
// This is used to track ad-hoc events that are not handled by the event server.
type DefaultHandler struct {
redisClient redis.UniversalClient
}

func (h *DefaultHandler) Path() string {
return "/"
}

func (h *DefaultHandler) HandlerFunc(w http.ResponseWriter, r *http.Request) {
sandboxID := r.Header.Get("E2B_SANDBOX_ID")

if r.Method == http.MethodGet {
body, err := h.redisClient.Get(r.Context(), sandboxID).Result()
if err != nil {
http.Error(w, "Failed to get event data for sandbox "+sandboxID, http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte(body))
return
}

if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}

// Create event data with path and body
eventData := EventData{
Path: r.URL.Path,
}

body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Failed to read request body", http.StatusInternalServerError)
return
}

eventData.Body = make(map[string]any)
err = json.Unmarshal(body, &eventData.Body)
if err != nil {
http.Error(w, "Failed to unmarshal request body", http.StatusInternalServerError)
return
}

// Store in Redis with sandboxID as key
err = h.redisClient.Set(r.Context(), sandboxID, eventData, 0).Err()
if err != nil {
http.Error(w, "Failed to store event data", http.StatusInternalServerError)
return
}

w.WriteHeader(http.StatusCreated)
w.Write([]byte(`{"event_ack":true}`))
}

func NewEventHandlers(redisClient redis.UniversalClient) []EventHandler {
return []EventHandler{
&MetricsHandler{},
&DefaultHandler{redisClient},
}
}
65 changes: 65 additions & 0 deletions packages/orchestrator/internal/sandbox/event/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package event

import (
"context"
"fmt"
"net/http"

"go.uber.org/zap"
)

// EventServer handles outbound HTTP requests from sandboxes calling the event.e2b.com endpoint
type EventServer struct {
server *http.Server
}

func validateHeaders(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
sandboxID := r.Header.Get("E2B_SANDBOX_ID")
teamID := r.Header.Get("E2B_TEAM_ID")

if sandboxID == "" || teamID == "" {
http.Error(w, "missing required headers", http.StatusBadRequest)
return
}

next.ServeHTTP(w, r)
}
}

func NewEventServer(port uint, handlers []EventHandler) *EventServer {
mux := http.NewServeMux()

for _, handler := range handlers {
mux.HandleFunc(handler.Path(), validateHeaders(handler.HandlerFunc))
}

server := &http.Server{
Addr: fmt.Sprintf(":%d", port),
Handler: mux,
}
Comment on lines +21 to +24
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about running Gin here so we can use a strict Golang client in envd and track all version changes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, we can use gin, but i'm not sure it's more strict than the std lib and also what do u mean by tracking version changes in this case?

Copy link
Member

@sitole sitole Jul 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but i'm not sure it's more strict than the std lib and also what do u mean by tracking version changes in this case?

I was thinking that the "metrics server" can be Gin-backed by the OpenAPI scheme, as we are using for the API, so all breaking changes will be clear (because of the re-generated schema). You will also be able to use the generated Go client from EnvD to call metrics service endpoints.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point was just make it strong types on both caller and receiver

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with @sitole


return &EventServer{
server: server,
}
}

func (p *EventServer) Start() error {
zap.L().Info("Starting event server")
return p.server.ListenAndServe()
}

func (p *EventServer) Close(ctx context.Context) error {
var err error
select {
case <-ctx.Done():
err = p.server.Close()
default:
err = p.server.Shutdown(ctx)
}
if err != nil {
return fmt.Errorf("failed to shutdown event server: %w", err)
}

return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,12 @@ func (s *Slot) CreateNetwork() error {
return fmt.Errorf("error creating postrouting rule: %w", err)
}

// Redirect http://event.e2b.dev traffic destined to event server
err = tables.Append("nat", "PREROUTING", "-i", s.VethName(), "-p", "tcp", "-d", "8.8.8.7", "--dport", "80", "-j", "REDIRECT", "--to-port", "5010")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use different IP than 8.8.8.7, I guess any IP from these should be more appropriate:

var blockedRanges = []string{
	"10.0.0.0/8",
	"169.254.0.0/16",
	"192.168.0.0/16",
	"172.16.0.0/12",
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ideally yes, i first tried private IPs, they don't leave the sandbox through the network bridge with current setup, i'd have to figure out a way to route one of the private ones this way.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just note, these ranges are blocked by default, you need to enable the target IP address (maybe that might be why you haven't seen them routed)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we maybe not use public IP, but something like metadata IP used by envd for accessing Firecracker VM metadata?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More details on why Firecracker and cloud providers are using 169.254/16 https://datatracker.ietf.org/doc/html/rfc3927

Copy link
Member

@sitole sitole Jul 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps provide the domain as an environment variable via envd so we are not locked into it for the future? Then does not matter what domain we will use now

Copy link
Contributor

@dobrac dobrac Jul 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does matter in a sense where it will be encoded in all envds

Copy link
Member

@sitole sitole Jul 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does matter in a sense where it will be encoded in all envds

That was my point with Perhaps provide the domain as an environment variable via envd so we are not locked into it for the future

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, you mean through MMDS, not environment variable, correct?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, sorry for confusion

if err != nil {
return fmt.Errorf("error creating HTTP redirect rule to sandbox event server: %w", err)
}

return nil
}

Expand Down
2 changes: 2 additions & 0 deletions packages/orchestrator/internal/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/e2b-dev/infra/packages/orchestrator/internal/grpcserver"
"github.com/e2b-dev/infra/packages/orchestrator/internal/proxy"
"github.com/e2b-dev/infra/packages/orchestrator/internal/sandbox"
"github.com/e2b-dev/infra/packages/orchestrator/internal/sandbox/event"
"github.com/e2b-dev/infra/packages/orchestrator/internal/sandbox/nbd"
"github.com/e2b-dev/infra/packages/orchestrator/internal/sandbox/network"
"github.com/e2b-dev/infra/packages/orchestrator/internal/sandbox/template"
Expand Down Expand Up @@ -61,6 +62,7 @@ func New(
tracer trace.Tracer,
info *service.ServiceInfo,
proxy *proxy.SandboxProxy,
eventServer *event.EventServer,
sandboxes *smap.Map[*sandbox.Sandbox],
sandboxObserver *telemetry.SandboxObserver,
featureFlags *featureflags.Client,
Expand Down
4 changes: 3 additions & 1 deletion packages/orchestrator/internal/template/build/rootfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ ExecStart=-/sbin/agetty --noissue --autologin root %I 115200,38400,9600 vt102
`

hostname := "e2b.local"
eventProxyHostname := "event.e2b.dev"

hosts := fmt.Sprintf(`127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
Expand All @@ -205,7 +206,8 @@ ff00:: ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
127.0.1.1 %s
`, hostname)
8.8.8.7 %s
`, hostname, eventProxyHostname)

e2bFile := fmt.Sprintf(`ENV_ID=%s
BUILD_ID=%s
Expand Down
49 changes: 44 additions & 5 deletions packages/orchestrator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"slices"
"syscall"
"time"

Check failure on line 16 in packages/orchestrator/main.go

View workflow job for this annotation

GitHub Actions / lint / golangci-lint (/home/runner/work/infra/infra/packages/orchestrator)

File is not properly formatted (gci)
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"golang.org/x/sync/errgroup"
Expand All @@ -21,6 +21,7 @@
"github.com/e2b-dev/infra/packages/orchestrator/internal/grpcserver"
"github.com/e2b-dev/infra/packages/orchestrator/internal/proxy"
"github.com/e2b-dev/infra/packages/orchestrator/internal/sandbox"
"github.com/e2b-dev/infra/packages/orchestrator/internal/sandbox/event"
"github.com/e2b-dev/infra/packages/orchestrator/internal/sandbox/nbd"
"github.com/e2b-dev/infra/packages/orchestrator/internal/sandbox/network"
"github.com/e2b-dev/infra/packages/orchestrator/internal/server"
Expand All @@ -33,15 +34,17 @@
sbxlogger "github.com/e2b-dev/infra/packages/shared/pkg/logger/sandbox"
"github.com/e2b-dev/infra/packages/shared/pkg/smap"
"github.com/e2b-dev/infra/packages/shared/pkg/telemetry"
"github.com/redis/go-redis/v9"
)

type Closeable interface {
Close(context.Context) error
}

const (
defaultPort = 5008
defaultProxyPort = 5007
defaultPort = 5008
defaultProxyPort = 5007
defaultEventProxyPort = 5010

sandboxMetricExportPeriod = 5 * time.Second

Expand All @@ -58,6 +61,7 @@
func main() {
port := flag.Uint("port", defaultPort, "orchestrator server port")
proxyPort := flag.Uint("proxy-port", defaultProxyPort, "orchestrator proxy port")
eventProxyPort := flag.Uint("event-proxy-port", defaultEventProxyPort, "orchestrator event proxy port")
flag.Parse()

if *port > math.MaxUint16 {
Expand All @@ -68,7 +72,7 @@
log.Fatalf("%d is larger than maximum possible proxy port %d", proxyPort, math.MaxInt16)
}

success := run(*port, *proxyPort)
success := run(*port, *proxyPort, *eventProxyPort)

log.Println("Stopping orchestrator, success:", success)

Expand All @@ -77,7 +81,7 @@
}
}

func run(port, proxyPort uint) (success bool) {
func run(port, proxyPort, sbxEventServerPort uint) (success bool) {
success = true

services := service.GetServices()
Expand Down Expand Up @@ -218,6 +222,25 @@
zap.L().Fatal("failed to create sandbox proxy", zap.Error(err))
}

var redisClient redis.UniversalClient
if redisClusterUrl := os.Getenv("REDIS_CLUSTER_URL"); redisClusterUrl != "" {
redisClient = redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{redisClusterUrl},
MinIdleConns: 1,
})
} else if redisUrl := os.Getenv("REDIS_URL"); redisUrl != "" {
redisClient = redis.NewClient(&redis.Options{
Addr: redisUrl,
MinIdleConns: 1,
})
} else {
zap.L().Fatal("REDIS_URL not set")
}

sbxEventHandlers := event.NewEventHandlers(redisClient)

sbxEventServer := event.NewEventServer(sbxEventServerPort, sbxEventHandlers)

tracer := tel.TracerProvider.Tracer(serviceName)

networkPool, err := network.NewPool(ctx, tel.MeterProvider, network.NewSlotsPoolSize, network.ReusedSlotsPoolSize, clientID, tracer)
Expand All @@ -244,7 +267,7 @@
zap.L().Fatal("failed to create sandbox observer", zap.Error(err))
}

_, err = server.New(ctx, grpcSrv, tel, networkPool, devicePool, tracer, serviceInfo, sandboxProxy, sandboxes, sandboxObserver, featureFlags)
_, err = server.New(ctx, grpcSrv, tel, networkPool, devicePool, tracer, serviceInfo, sandboxProxy, sbxEventServer, sandboxes, sandboxObserver, featureFlags)
if err != nil {
zap.L().Fatal("failed to create server", zap.Error(err))
}
Expand Down Expand Up @@ -320,6 +343,22 @@
return nil
})

g.Go(func() error {
sbxEventServerErr := sbxEventServer.Start()
if sbxEventServerErr != nil && !errors.Is(sbxEventServerErr, http.ErrServerClosed) {
select {
case serviceError <- sbxEventServerErr:
default:
// Don't block if the serviceError channel is already closed
// or if the error is already sent
}

return sbxEventServerErr
}

return nil
})

g.Go(func() (err error) {
// this sets the error declared above so the function
// in the defer can check it.
Expand Down
Loading