7
7
"strings"
8
8
"sync"
9
9
10
+ "golang.org/x/sync/errgroup"
10
11
"golang.org/x/xerrors"
11
12
12
13
"github.com/google/uuid"
@@ -62,141 +63,106 @@ type Deps struct {
62
63
}
63
64
64
65
func DeploymentInfo (ctx context.Context , client * codersdk.Client , log slog.Logger ) Deployment {
65
- var (
66
- d Deployment
67
- m sync.Mutex
68
- wg sync.WaitGroup
69
- )
70
-
71
- wg .Add (1 )
72
- go func () {
73
- defer wg .Done ()
66
+ // Note: each goroutine assigns to a different struct field, hence no mutex.
67
+ var d Deployment
68
+ eg , ctx := errgroup .WithContext (ctx )
69
+ eg .Go (func () error {
74
70
bi , err := client .BuildInfo (ctx )
75
71
if err != nil {
76
- log .Error (ctx , "fetch build info" , slog .Error (err ))
77
- return
72
+ return xerrors .Errorf ("fetch build info: %w" , err )
78
73
}
79
- m .Lock ()
80
74
d .BuildInfo = & bi
81
- m . Unlock ()
82
- }( )
75
+ return nil
76
+ })
83
77
84
- wg .Add (1 )
85
- go func () {
86
- defer wg .Done ()
78
+ eg .Go (func () error {
87
79
dc , err := client .DeploymentConfig (ctx )
88
80
if err != nil {
89
- log .Error (ctx , "fetch deployment config" , slog .Error (err ))
90
- return
81
+ return xerrors .Errorf ("fetch deployment config: %w" , err )
91
82
}
92
- m .Lock ()
93
83
d .Config = dc
94
- m . Unlock ()
95
- }( )
84
+ return nil
85
+ })
96
86
97
- wg .Add (1 )
98
- go func () {
99
- defer wg .Done ()
87
+ eg .Go (func () error {
100
88
hr , err := client .DebugHealth (ctx )
101
89
if err != nil {
102
- log .Error (ctx , "fetch health report" , slog .Error (err ))
103
- return
90
+ return xerrors .Errorf ("fetch health report: %w" , err )
104
91
}
105
- m .Lock ()
106
92
d .HealthReport = & hr
107
- m . Unlock ()
108
- }( )
93
+ return nil
94
+ })
109
95
110
- wg .Add (1 )
111
- go func () {
112
- defer wg .Done ()
96
+ eg .Go (func () error {
113
97
exp , err := client .Experiments (ctx )
114
98
if err != nil {
115
- log .Error (ctx , "fetch experiments" , slog .Error (err ))
116
- return
99
+ return xerrors .Errorf ("fetch experiments: %w" , err )
117
100
}
118
- m .Lock ()
119
101
d .Experiments = exp
120
- m .Unlock ()
121
- }()
102
+ return nil
103
+ })
104
+
105
+ if err := eg .Wait (); err != nil {
106
+ log .Error (ctx , "fetch deployment information" , slog .Error (err ))
107
+ }
122
108
123
- wg .Wait ()
124
109
return d
125
110
}
126
111
127
112
func NetworkInfo (ctx context.Context , client * codersdk.Client , log slog.Logger , agentID uuid.UUID ) Network {
128
- var (
129
- n Network
130
- m sync.Mutex
131
- wg sync.WaitGroup
132
- )
113
+ var n Network
133
114
134
- wg .Add (1 )
135
- go func () {
136
- defer wg .Done ()
115
+ eg , ctx := errgroup .WithContext (ctx )
116
+ eg .Go (func () error {
137
117
coordResp , err := client .Request (ctx , http .MethodGet , "/api/v2/debug/coordinator" , nil )
138
118
if err != nil {
139
- log .Error (ctx , "fetch coordinator debug page" , slog .Error (err ))
140
- return
119
+ return xerrors .Errorf ("fetch coordinator debug page: %w" , err )
141
120
}
142
121
defer coordResp .Body .Close ()
143
122
bs , err := io .ReadAll (coordResp .Body )
144
123
if err != nil {
145
- log .Error (ctx , "read coordinator debug page" , slog .Error (err ))
146
- return
124
+ return xerrors .Errorf ("read coordinator debug page: %w" , err )
147
125
}
148
- m .Lock ()
149
126
n .CoordinatorDebug = string (bs )
150
- m . Unlock ()
151
- }( )
127
+ return nil
128
+ })
152
129
153
- wg .Add (1 )
154
- go func () {
155
- defer wg .Done ()
130
+ eg .Go (func () error {
156
131
tailResp , err := client .Request (ctx , http .MethodGet , "/api/v2/debug/tailnet" , nil )
157
132
if err != nil {
158
- log .Error (ctx , "fetch tailnet debug page" , slog .Error (err ))
159
- return
133
+ return xerrors .Errorf ("fetch tailnet debug page: %w" , err )
160
134
}
161
135
defer tailResp .Body .Close ()
162
136
bs , err := io .ReadAll (tailResp .Body )
163
137
if err != nil {
164
- log .Error (ctx , "read tailnet debug page" , slog .Error (err ))
165
- return
138
+ return xerrors .Errorf ("read tailnet debug page: %w" , err )
166
139
}
167
- m .Lock ()
168
140
n .TailnetDebug = string (bs )
169
- m . Unlock ()
170
- }( )
141
+ return nil
142
+ })
171
143
172
- wg .Add (1 )
173
- go func () {
174
- defer wg .Done ()
144
+ eg .Go (func () error {
175
145
if agentID == uuid .Nil {
176
146
log .Warn (ctx , "agent id required for agent connection info" )
177
- return
147
+ return nil
178
148
}
179
149
connInfo , err := client .WorkspaceAgentConnectionInfo (ctx , agentID )
180
150
if err != nil {
181
- log .Error (ctx , "fetch agent conn info" , slog .Error (err ), slog .F ("agent_id" , agentID .String ()))
182
- return
151
+ return xerrors .Errorf ("fetch agent conn info: %w" , err )
183
152
}
184
- m .Lock ()
185
153
n .NetcheckLocal = & connInfo
186
- m . Unlock ()
187
- }( )
154
+ return nil
155
+ })
188
156
189
- wg .Wait ()
157
+ if err := eg .Wait (); err != nil {
158
+ log .Error (ctx , "fetch network information" , slog .Error (err ))
159
+ }
190
160
191
161
return n
192
162
}
193
163
194
164
func WorkspaceInfo (ctx context.Context , client * codersdk.Client , log slog.Logger , workspaceID , agentID uuid.UUID ) Workspace {
195
- var (
196
- w Workspace
197
- m sync.Mutex
198
- wg sync.WaitGroup
199
- )
165
+ var w Workspace
200
166
201
167
if workspaceID == uuid .Nil {
202
168
log .Error (ctx , "no workspace id specified" )
@@ -215,58 +181,52 @@ func WorkspaceInfo(ctx context.Context, client *codersdk.Client, log slog.Logger
215
181
}
216
182
w .Workspace = ws
217
183
218
- wg . Add ( 1 )
219
- go func () {
220
- defer wg . Done ()
184
+ eg , ctx := errgroup . WithContext ( ctx )
185
+
186
+ eg . Go ( func () error {
221
187
agt , err := client .WorkspaceAgent (ctx , agentID )
222
188
if err != nil {
223
- log . Error ( ctx , "fetch workspace agent" , slog . Error ( err ), slog . F ( "agent_id" , agentID ) )
189
+ return xerrors . Errorf ( "fetch workspace agent: %w" , err )
224
190
}
225
- m .Lock ()
226
191
w .Agent = agt
227
- m . Unlock ()
228
- }( )
192
+ return nil
193
+ })
229
194
230
- wg .Add (1 )
231
- go func () {
232
- defer wg .Done ()
195
+ eg .Go (func () error {
233
196
buildLogCh , closer , err := client .WorkspaceBuildLogsAfter (ctx , ws .LatestBuild .ID , 0 )
234
197
if err != nil {
235
- log .Error (ctx , "fetch provisioner job logs" , slog .Error (err ), slog .F ("job_id" , ws .LatestBuild .Job .ID .String ()))
236
- return
198
+ return xerrors .Errorf ("fetch provisioner job logs: %w" , err )
237
199
}
238
200
defer closer .Close ()
239
201
var logs []codersdk.ProvisionerJobLog
240
202
for log := range buildLogCh {
241
203
logs = append (w .BuildLogs , log )
242
204
}
243
- m .Lock ()
244
205
w .BuildLogs = logs
245
- m . Unlock ()
246
- }( )
206
+ return nil
207
+ })
247
208
248
- wg .Add (1 )
249
- go func () {
250
- defer wg .Done ()
209
+ eg .Go (func () error {
251
210
if len (w .Workspace .LatestBuild .Resources ) == 0 {
252
211
log .Warn (ctx , "workspace build has no resources" )
253
- return
212
+ return nil
254
213
}
255
214
agentLogCh , closer , err := client .WorkspaceAgentLogsAfter (ctx , agentID , 0 , false )
256
215
if err != nil {
257
- log . Error ( ctx , "fetch agent startup logs" , slog . Error ( err ), slog . F ( "agent_id" , agentID . String ()) )
216
+ return xerrors . Errorf ( "fetch agent startup logs: %w" , err )
258
217
}
259
218
defer closer .Close ()
260
219
var logs []codersdk.WorkspaceAgentLog
261
220
for logChunk := range agentLogCh {
262
221
logs = append (w .AgentStartupLogs , logChunk ... )
263
222
}
264
- m .Lock ()
265
223
w .AgentStartupLogs = logs
266
- m . Unlock ()
267
- }( )
224
+ return nil
225
+ })
268
226
269
- wg .Wait ()
227
+ if err := eg .Wait (); err != nil {
228
+ log .Error (ctx , "fetch workspace information" , slog .Error (err ))
229
+ }
270
230
271
231
return w
272
232
}
0 commit comments