-
Notifications
You must be signed in to change notification settings - Fork 481
feat(contrib/haproxy): Add HAProxy SPOE Agent binary #3913
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: flavien/contrib/haproxy
Are you sure you want to change the base?
Conversation
b701767
to
e3b62d8
Compare
BenchmarksBenchmark execution time: 2025-09-22 13:08:17 Comparing candidate commit 8e19c42 in PR branch Found 0 performance improvements and 0 performance regressions! Performance is the same for 24 metrics, 0 unstable metrics. |
469c32d
to
9ee5626
Compare
c61f014
to
0535995
Compare
6c40e5f
to
5fce2b7
Compare
fbcebc8
to
cfdef7a
Compare
b89b146
to
3e7de4a
Compare
d1b24d6
to
0b2ffdc
Compare
2664229
to
d4759de
Compare
@codex review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Codex Review: Here are some suggestions.
Reply with @codex fix comments
to fix any unresolved comments.
About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you open a pull request for review, mark a draft as ready, or comment "@codex review". If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex fix this CI failure" or "@codex address that feedback".
func startService(config haProxySpoaConfig) error { | ||
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) | ||
defer cancel() | ||
g, ctx := errgroup.WithContext(ctx) | ||
|
||
g.Go(func() error { | ||
return startSpoa(ctx, config) | ||
}) | ||
|
||
g.Go(func() error { | ||
return startHealthCheck(ctx, config) | ||
}) | ||
|
||
if err := g.Wait(); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func startHealthCheck(ctx context.Context, config haProxySpoaConfig) error { | ||
muxServer := http.NewServeMux() | ||
muxServer.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) { | ||
w.Header().Set("Content-Type", "application/json") | ||
w.WriteHeader(http.StatusOK) | ||
w.Write([]byte(`{"status": "ok", "library": {"language": "golang", "version": "` + instrumentation.Version() + `"}}`)) | ||
}) | ||
|
||
server := &http.Server{ | ||
Addr: config.extensionHost + ":" + config.healthcheckPort, | ||
Handler: muxServer, | ||
} | ||
|
||
go func() { | ||
<-ctx.Done() | ||
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) | ||
defer cancel() | ||
if err := server.Shutdown(shutdownCtx); err != nil { | ||
log.Error("haproxy_spoa: health check server shutdown: %s\n", err.Error()) | ||
} | ||
}() | ||
|
||
log.Info("haproxy_spoa: health check server started on %s:%s\n", config.extensionHost, config.healthcheckPort) | ||
if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { | ||
return fmt.Errorf("health check http server: %s", err.Error()) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func startSpoa(ctx context.Context, config haProxySpoaConfig) error { | ||
listener, err := net.Listen("tcp4", config.extensionHost+":"+config.extensionPort) | ||
if err != nil { | ||
return fmt.Errorf("error creating listener: %w", err) | ||
} | ||
defer listener.Close() | ||
|
||
_ = tracer.Start(tracer.WithAppSecEnabled(true)) | ||
defer tracer.Stop() | ||
|
||
appsecHAProxy := streamprocessingoffload.NewHAProxySPOA(streamprocessingoffload.AppsecHAProxyConfig{ | ||
BlockingUnavailable: false, | ||
BodyParsingSizeLimit: config.bodyParsingSizeLimit, | ||
Context: ctx, | ||
}) | ||
|
||
a := agent.New(appsecHAProxy.Handler, log) | ||
|
||
log.Info("haproxy_spoa: datadog agent server started on %s:%s\n", config.extensionHost, config.extensionPort) | ||
if err := a.Serve(listener); err != nil { | ||
return fmt.Errorf("error starting agent server: %w", err) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[P1] Stop SPOA listener when shutdown context is cancelled
The new HAProxy SPOA command wires both the SPOA server and health check into an errgroup driven by signal.NotifyContext
, but startSpoa
never observes that context. Once the health check goroutine shuts down, a.Serve(listener)
continues to block on the TCP listener even after SIGINT/SIGTERM, causing startService
to hang and the process to ignore termination requests unless the listener fails or the process is killed. Closing the listener or otherwise stopping the agent when ctx.Done()
fires would allow g.Wait()
to return and the program to exit cleanly.
Useful? React with 👍 / 👎.
0b2ffdc
to
8e19c42
Compare
What does this PR do?
Motivation
Reviewer's Checklist
./scripts/lint.sh
locally.Unsure? Have a question? Request a review!