Skip to content

Commit 326bef4

Browse files
authored
Merge pull request #320 from gitpod-io/wv/graceful-otel-shutdown-on-failure
Graceful otel shutdown on build failure
2 parents 8206b4e + d3881f8 commit 326bef4

File tree

2 files changed

+81
-58
lines changed

2 files changed

+81
-58
lines changed

cmd/build.go

Lines changed: 80 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,101 @@ 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+
cancel()
84+
return err
7585
}
86+
}
87+
if serve != "" {
88+
go serveBuildResult(ctx, serve, localCache, pkg)
89+
}
7690

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)
91+
evt, errs := leeway.WatchSources(context.Background(), append(pkg.GetTransitiveDependencies(), pkg), 2*time.Second)
92+
for {
93+
select {
94+
case <-evt:
95+
_, pkg, _, _ := getTarget(args, false)
96+
err := leeway.Build(pkg, opts...)
97+
if err == nil {
98+
cancel()
99+
ctx, cancel = context.WithCancel(context.Background())
100+
if save != "" {
101+
err = saveBuildResult(ctx, save, localCache, pkg)
102+
if err != nil {
103+
cancel()
104+
return err
91105
}
92-
} else {
93-
log.Error(err)
94106
}
95-
case err = <-errs:
96-
log.Fatal(err)
107+
if serve != "" {
108+
go serveBuildResult(ctx, serve, localCache, pkg)
109+
}
110+
} else {
111+
log.Error(err)
97112
}
113+
case err = <-errs:
114+
cancel()
115+
return err
98116
}
99117
}
118+
}
100119

101-
err := leeway.Build(pkg, opts...)
120+
err := leeway.Build(pkg, opts...)
121+
if err != nil {
122+
return err
123+
}
124+
if save != "" {
125+
err = saveBuildResult(context.Background(), save, localCache, pkg)
102126
if err != nil {
103-
log.Fatal(err)
127+
return err
104128
}
105-
if save != "" {
106-
saveBuildResult(context.Background(), save, localCache, pkg)
107-
}
108-
if serve != "" {
109-
serveBuildResult(context.Background(), serve, localCache, pkg)
110-
}
111-
},
129+
}
130+
if serve != "" {
131+
serveBuildResult(context.Background(), serve, localCache, pkg)
132+
}
133+
return nil
112134
}
113135

114136
func serveBuildResult(ctx context.Context, addr string, localCache cache.LocalCache, pkg *leeway.Package) {
@@ -148,30 +170,31 @@ func serveBuildResult(ctx context.Context, addr string, localCache cache.LocalCa
148170
}
149171
}
150172

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

157179
fout, err := os.OpenFile(loc, os.O_CREATE|os.O_WRONLY, 0644)
158180
if err != nil {
159-
log.WithError(err).Fatal("cannot open result file for writing")
181+
return fmt.Errorf("cannot open result file for writing: %w", err)
160182
}
161183
fin, err := os.OpenFile(br, os.O_RDONLY, 0644)
162184
if err != nil {
163185
fout.Close()
164-
log.WithError(err).Fatal("cannot copy build result")
186+
return fmt.Errorf("cannot copy build result: %w", err)
165187
}
166188

167189
_, err = io.Copy(fout, fin)
168190
fout.Close()
169191
fin.Close()
170192
if err != nil {
171-
log.WithError(err).Fatal("cannot copy build result")
193+
return fmt.Errorf("cannot copy build result: %w", err)
172194
}
173195

174196
fmt.Printf("\n💾 saving build result to %s\n", color.Cyan.Render(loc))
197+
return nil
175198
}
176199

177200
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)