Skip to content

Commit 5106d9f

Browse files
authored
feat(support): fetch data concurrently (#12385)
Modifies pkg support to fetch data concurrently
1 parent fb88fa8 commit 5106d9f

File tree

1 file changed

+133
-73
lines changed

1 file changed

+133
-73
lines changed

support/support.go

+133-73
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"net/http"
77
"strings"
88

9+
"golang.org/x/sync/errgroup"
910
"golang.org/x/xerrors"
1011

1112
"github.com/google/uuid"
@@ -61,84 +62,114 @@ type Deps struct {
6162
}
6263

6364
func DeploymentInfo(ctx context.Context, client *codersdk.Client, log slog.Logger) Deployment {
64-
var d Deployment
65-
66-
bi, err := client.BuildInfo(ctx)
67-
if err != nil {
68-
log.Error(ctx, "fetch build info", slog.Error(err))
69-
} else {
65+
// Note: each goroutine assigns to a different struct field, hence no mutex.
66+
var (
67+
d Deployment
68+
eg errgroup.Group
69+
)
70+
71+
eg.Go(func() error {
72+
bi, err := client.BuildInfo(ctx)
73+
if err != nil {
74+
return xerrors.Errorf("fetch build info: %w", err)
75+
}
7076
d.BuildInfo = &bi
71-
}
77+
return nil
78+
})
7279

73-
dc, err := client.DeploymentConfig(ctx)
74-
if err != nil {
75-
log.Error(ctx, "fetch deployment config", slog.Error(err))
76-
} else {
80+
eg.Go(func() error {
81+
dc, err := client.DeploymentConfig(ctx)
82+
if err != nil {
83+
return xerrors.Errorf("fetch deployment config: %w", err)
84+
}
7785
d.Config = dc
78-
}
86+
return nil
87+
})
7988

80-
hr, err := client.DebugHealth(ctx)
81-
if err != nil {
82-
log.Error(ctx, "fetch health report", slog.Error(err))
83-
} else {
89+
eg.Go(func() error {
90+
hr, err := client.DebugHealth(ctx)
91+
if err != nil {
92+
return xerrors.Errorf("fetch health report: %w", err)
93+
}
8494
d.HealthReport = &hr
85-
}
95+
return nil
96+
})
8697

87-
exp, err := client.Experiments(ctx)
88-
if err != nil {
89-
log.Error(ctx, "fetch experiments", slog.Error(err))
90-
} else {
98+
eg.Go(func() error {
99+
exp, err := client.Experiments(ctx)
100+
if err != nil {
101+
return xerrors.Errorf("fetch experiments: %w", err)
102+
}
91103
d.Experiments = exp
104+
return nil
105+
})
106+
107+
if err := eg.Wait(); err != nil {
108+
log.Error(ctx, "fetch deployment information", slog.Error(err))
92109
}
93110

94111
return d
95112
}
96113

97114
func NetworkInfo(ctx context.Context, client *codersdk.Client, log slog.Logger, agentID uuid.UUID) Network {
98-
var n Network
115+
var (
116+
n Network
117+
eg errgroup.Group
118+
)
99119

100-
coordResp, err := client.Request(ctx, http.MethodGet, "/api/v2/debug/coordinator", nil)
101-
if err != nil {
102-
log.Error(ctx, "fetch coordinator debug page", slog.Error(err))
103-
} else {
120+
eg.Go(func() error {
121+
coordResp, err := client.Request(ctx, http.MethodGet, "/api/v2/debug/coordinator", nil)
122+
if err != nil {
123+
return xerrors.Errorf("fetch coordinator debug page: %w", err)
124+
}
104125
defer coordResp.Body.Close()
105126
bs, err := io.ReadAll(coordResp.Body)
106127
if err != nil {
107-
log.Error(ctx, "read coordinator debug page", slog.Error(err))
108-
} else {
109-
n.CoordinatorDebug = string(bs)
128+
return xerrors.Errorf("read coordinator debug page: %w", err)
110129
}
111-
}
130+
n.CoordinatorDebug = string(bs)
131+
return nil
132+
})
112133

113-
tailResp, err := client.Request(ctx, http.MethodGet, "/api/v2/debug/tailnet", nil)
114-
if err != nil {
115-
log.Error(ctx, "fetch tailnet debug page", slog.Error(err))
116-
} else {
134+
eg.Go(func() error {
135+
tailResp, err := client.Request(ctx, http.MethodGet, "/api/v2/debug/tailnet", nil)
136+
if err != nil {
137+
return xerrors.Errorf("fetch tailnet debug page: %w", err)
138+
}
117139
defer tailResp.Body.Close()
118140
bs, err := io.ReadAll(tailResp.Body)
119141
if err != nil {
120-
log.Error(ctx, "read tailnet debug page", slog.Error(err))
121-
} else {
122-
n.TailnetDebug = string(bs)
142+
return xerrors.Errorf("read tailnet debug page: %w", err)
143+
}
144+
n.TailnetDebug = string(bs)
145+
return nil
146+
})
147+
148+
eg.Go(func() error {
149+
if agentID == uuid.Nil {
150+
log.Warn(ctx, "agent id required for agent connection info")
151+
return nil
123152
}
124-
}
125-
126-
if agentID != uuid.Nil {
127153
connInfo, err := client.WorkspaceAgentConnectionInfo(ctx, agentID)
128154
if err != nil {
129-
log.Error(ctx, "fetch agent conn info", slog.Error(err), slog.F("agent_id", agentID.String()))
130-
} else {
131-
n.NetcheckLocal = &connInfo
155+
return xerrors.Errorf("fetch agent conn info: %w", err)
132156
}
133-
} else {
134-
log.Warn(ctx, "agent id required for agent connection info")
157+
n.NetcheckLocal = &connInfo
158+
return nil
159+
})
160+
161+
if err := eg.Wait(); err != nil {
162+
log.Error(ctx, "fetch network information", slog.Error(err))
135163
}
136164

137165
return n
138166
}
139167

140168
func WorkspaceInfo(ctx context.Context, client *codersdk.Client, log slog.Logger, workspaceID, agentID uuid.UUID) Workspace {
141-
var w Workspace
169+
var (
170+
w Workspace
171+
eg errgroup.Group
172+
)
142173

143174
if workspaceID == uuid.Nil {
144175
log.Error(ctx, "no workspace id specified")
@@ -149,43 +180,57 @@ func WorkspaceInfo(ctx context.Context, client *codersdk.Client, log slog.Logger
149180
log.Error(ctx, "no agent id specified")
150181
}
151182

183+
// dependency, cannot fetch concurrently
152184
ws, err := client.Workspace(ctx, workspaceID)
153185
if err != nil {
154186
log.Error(ctx, "fetch workspace", slog.Error(err), slog.F("workspace_id", workspaceID))
155187
return w
156188
}
157-
158-
agt, err := client.WorkspaceAgent(ctx, agentID)
159-
if err != nil {
160-
log.Error(ctx, "fetch workspace agent", slog.Error(err), slog.F("agent_id", agentID))
161-
}
162-
163189
w.Workspace = ws
164-
w.Agent = agt
165190

166-
buildLogCh, closer, err := client.WorkspaceBuildLogsAfter(ctx, ws.LatestBuild.ID, 0)
167-
if err != nil {
168-
log.Error(ctx, "fetch provisioner job logs", slog.Error(err), slog.F("job_id", ws.LatestBuild.Job.ID.String()))
169-
} else {
191+
eg.Go(func() error {
192+
agt, err := client.WorkspaceAgent(ctx, agentID)
193+
if err != nil {
194+
return xerrors.Errorf("fetch workspace agent: %w", err)
195+
}
196+
w.Agent = agt
197+
return nil
198+
})
199+
200+
eg.Go(func() error {
201+
buildLogCh, closer, err := client.WorkspaceBuildLogsAfter(ctx, ws.LatestBuild.ID, 0)
202+
if err != nil {
203+
return xerrors.Errorf("fetch provisioner job logs: %w", err)
204+
}
170205
defer closer.Close()
206+
var logs []codersdk.ProvisionerJobLog
171207
for log := range buildLogCh {
172-
w.BuildLogs = append(w.BuildLogs, log)
208+
logs = append(w.BuildLogs, log)
209+
}
210+
w.BuildLogs = logs
211+
return nil
212+
})
213+
214+
eg.Go(func() error {
215+
if len(w.Workspace.LatestBuild.Resources) == 0 {
216+
log.Warn(ctx, "workspace build has no resources")
217+
return nil
218+
}
219+
agentLogCh, closer, err := client.WorkspaceAgentLogsAfter(ctx, agentID, 0, false)
220+
if err != nil {
221+
return xerrors.Errorf("fetch agent startup logs: %w", err)
173222
}
174-
}
175-
176-
if len(w.Workspace.LatestBuild.Resources) == 0 {
177-
log.Warn(ctx, "workspace build has no resources")
178-
return w
179-
}
180-
181-
agentLogCh, closer, err := client.WorkspaceAgentLogsAfter(ctx, agentID, 0, false)
182-
if err != nil {
183-
log.Error(ctx, "fetch agent startup logs", slog.Error(err), slog.F("agent_id", agentID.String()))
184-
} else {
185223
defer closer.Close()
224+
var logs []codersdk.WorkspaceAgentLog
186225
for logChunk := range agentLogCh {
187-
w.AgentStartupLogs = append(w.AgentStartupLogs, logChunk...)
226+
logs = append(w.AgentStartupLogs, logChunk...)
188227
}
228+
w.AgentStartupLogs = logs
229+
return nil
230+
})
231+
232+
if err := eg.Wait(); err != nil {
233+
log.Error(ctx, "fetch workspace information", slog.Error(err))
189234
}
190235

191236
return w
@@ -225,9 +270,24 @@ func Run(ctx context.Context, d *Deps) (*Bundle, error) {
225270
}
226271
}
227272

228-
b.Deployment = DeploymentInfo(ctx, d.Client, d.Log)
229-
b.Workspace = WorkspaceInfo(ctx, d.Client, d.Log, d.WorkspaceID, d.AgentID)
230-
b.Network = NetworkInfo(ctx, d.Client, d.Log, d.AgentID)
273+
var eg errgroup.Group
274+
eg.Go(func() error {
275+
di := DeploymentInfo(ctx, d.Client, d.Log)
276+
b.Deployment = di
277+
return nil
278+
})
279+
eg.Go(func() error {
280+
wi := WorkspaceInfo(ctx, d.Client, d.Log, d.WorkspaceID, d.AgentID)
281+
b.Workspace = wi
282+
return nil
283+
})
284+
eg.Go(func() error {
285+
ni := NetworkInfo(ctx, d.Client, d.Log, d.AgentID)
286+
b.Network = ni
287+
return nil
288+
})
289+
290+
_ = eg.Wait()
231291

232292
return &b, nil
233293
}

0 commit comments

Comments
 (0)