Skip to content

Commit ee43598

Browse files
WVerlaekona-agent
andcommitted
Graceful otel shutdown on build failure
Co-authored-by: Ona <no-reply@ona.com>
1 parent 8206b4e commit ee43598

File tree

2 files changed

+78
-58
lines changed

2 files changed

+78
-58
lines changed

cmd/build.go

Lines changed: 77 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cmd
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"io"
78
"net/http"
@@ -35,80 +36,98 @@ var buildCmd = &cobra.Command{
3536
Docker Export Mode:
3637
By default, Docker packages with 'image' configuration push directly to registries.
3738
Use --docker-export-to-cache to export images to cache instead (enables SLSA L3).
38-
39+
3940
The LEEWAY_DOCKER_EXPORT_TO_CACHE environment variable sets the default for the flag.
4041
4142
Examples:
4243
# Build with Docker export mode enabled (CLI flag)
4344
leeway build --docker-export-to-cache :myapp
44-
45+
4546
# Build with Docker export mode enabled (environment variable)
4647
LEEWAY_DOCKER_EXPORT_TO_CACHE=true leeway build :myapp
47-
48+
4849
# Disable export mode even if env var is set
4950
leeway build --docker-export-to-cache=false :myapp`,
5051
Args: cobra.MaximumNArgs(1),
51-
Run: func(cmd *cobra.Command, args []string) {
52-
_, pkg, _, _ := getTarget(args, false)
53-
if pkg == nil {
54-
log.Fatal("build needs a package")
52+
RunE: func(cmd *cobra.Command, args []string) error {
53+
err := build(cmd, args)
54+
if err != nil {
55+
log.Fatal(err)
5556
}
56-
opts, localCache, shutdown := getBuildOpts(cmd)
57-
defer shutdown()
58-
59-
var (
60-
watch, _ = cmd.Flags().GetBool("watch")
61-
save, _ = cmd.Flags().GetString("save")
62-
serve, _ = cmd.Flags().GetString("serve")
63-
)
64-
if watch {
65-
err := leeway.Build(pkg, opts...)
57+
return nil
58+
},
59+
}
60+
61+
func build(cmd *cobra.Command, args []string) error {
62+
_, pkg, _, _ := getTarget(args, false)
63+
if pkg == nil {
64+
return errors.New("build needs a package")
65+
}
66+
opts, localCache, shutdown := getBuildOpts(cmd)
67+
defer shutdown()
68+
69+
var (
70+
watch, _ = cmd.Flags().GetBool("watch")
71+
save, _ = cmd.Flags().GetString("save")
72+
serve, _ = cmd.Flags().GetString("serve")
73+
)
74+
if watch {
75+
err := leeway.Build(pkg, opts...)
76+
if err != nil {
77+
return err
78+
}
79+
ctx, cancel := context.WithCancel(context.Background())
80+
if save != "" {
81+
err = saveBuildResult(ctx, save, localCache, pkg)
6682
if err != nil {
67-
log.Fatal(err)
68-
}
69-
ctx, cancel := context.WithCancel(context.Background())
70-
if save != "" {
71-
saveBuildResult(ctx, save, localCache, pkg)
72-
}
73-
if serve != "" {
74-
go serveBuildResult(ctx, serve, localCache, pkg)
83+
return err
7584
}
85+
}
86+
if serve != "" {
87+
go serveBuildResult(ctx, serve, localCache, pkg)
88+
}
7689

77-
evt, errs := leeway.WatchSources(context.Background(), append(pkg.GetTransitiveDependencies(), pkg), 2*time.Second)
78-
for {
79-
select {
80-
case <-evt:
81-
_, pkg, _, _ := getTarget(args, false)
82-
err := leeway.Build(pkg, opts...)
83-
if err == nil {
84-
cancel()
85-
ctx, cancel = context.WithCancel(context.Background())
86-
if save != "" {
87-
saveBuildResult(ctx, save, localCache, pkg)
88-
}
89-
if serve != "" {
90-
go serveBuildResult(ctx, serve, localCache, pkg)
90+
evt, errs := leeway.WatchSources(context.Background(), append(pkg.GetTransitiveDependencies(), pkg), 2*time.Second)
91+
for {
92+
select {
93+
case <-evt:
94+
_, pkg, _, _ := getTarget(args, false)
95+
err := leeway.Build(pkg, opts...)
96+
if err == nil {
97+
cancel()
98+
ctx, cancel = context.WithCancel(context.Background())
99+
if save != "" {
100+
err = saveBuildResult(ctx, save, localCache, pkg)
101+
if err != nil {
102+
return err
91103
}
92-
} else {
93-
log.Error(err)
94104
}
95-
case err = <-errs:
96-
log.Fatal(err)
105+
if serve != "" {
106+
go serveBuildResult(ctx, serve, localCache, pkg)
107+
}
108+
} else {
109+
log.Error(err)
97110
}
111+
case err = <-errs:
112+
return err
98113
}
99114
}
115+
}
100116

101-
err := leeway.Build(pkg, opts...)
117+
err := leeway.Build(pkg, opts...)
118+
if err != nil {
119+
return err
120+
}
121+
if save != "" {
122+
err = saveBuildResult(context.Background(), save, localCache, pkg)
102123
if err != nil {
103-
log.Fatal(err)
124+
return err
104125
}
105-
if save != "" {
106-
saveBuildResult(context.Background(), save, localCache, pkg)
107-
}
108-
if serve != "" {
109-
serveBuildResult(context.Background(), serve, localCache, pkg)
110-
}
111-
},
126+
}
127+
if serve != "" {
128+
serveBuildResult(context.Background(), serve, localCache, pkg)
129+
}
130+
return nil
112131
}
113132

114133
func serveBuildResult(ctx context.Context, addr string, localCache cache.LocalCache, pkg *leeway.Package) {
@@ -148,30 +167,31 @@ func serveBuildResult(ctx context.Context, addr string, localCache cache.LocalCa
148167
}
149168
}
150169

151-
func saveBuildResult(ctx context.Context, loc string, localCache cache.LocalCache, pkg *leeway.Package) {
170+
func saveBuildResult(ctx context.Context, loc string, localCache cache.LocalCache, pkg *leeway.Package) error {
152171
br, exists := localCache.Location(pkg)
153172
if !exists {
154-
log.Fatal("build result is not in local cache despite just being built. Something's wrong with the cache.")
173+
return errors.New("build result is not in local cache despite just being built. Something's wrong with the cache.")
155174
}
156175

157176
fout, err := os.OpenFile(loc, os.O_CREATE|os.O_WRONLY, 0644)
158177
if err != nil {
159-
log.WithError(err).Fatal("cannot open result file for writing")
178+
return fmt.Errorf("cannot open result file for writing: %w", err)
160179
}
161180
fin, err := os.OpenFile(br, os.O_RDONLY, 0644)
162181
if err != nil {
163182
fout.Close()
164-
log.WithError(err).Fatal("cannot copy build result")
183+
return fmt.Errorf("cannot copy build result: %w", err)
165184
}
166185

167186
_, err = io.Copy(fout, fin)
168187
fout.Close()
169188
fin.Close()
170189
if err != nil {
171-
log.WithError(err).Fatal("cannot copy build result")
190+
return fmt.Errorf("cannot copy build result: %w", err)
172191
}
173192

174193
fmt.Printf("\n💾 saving build result to %s\n", color.Cyan.Render(loc))
194+
return nil
175195
}
176196

177197
func init() {

pkg/leeway/build.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ func newBuildContext(options buildOptions) (ctx *buildContext, err error) {
131131

132132
// Ensure cache directory exists with proper permissions
133133
if err := os.MkdirAll(buildDir, 0755); err != nil {
134-
log.WithError(err).Fatal("failed to create build directory")
134+
return nil, xerrors.Errorf("failed to create build directory: %w", err)
135135
}
136136

137137
var buildLimit *semaphore.Weighted

0 commit comments

Comments
 (0)