(ctx context.Context)
| 1301 | } |
| 1302 | |
| 1303 | func (api *API) runEntitlementsLoop(ctx context.Context) { |
| 1304 | eb := backoff.NewExponentialBackOff() |
| 1305 | eb.MaxElapsedTime = 0 // retry indefinitely |
| 1306 | b := backoff.WithContext(eb, ctx) |
| 1307 | updates := make(chan struct{}, 1) |
| 1308 | subscribed := false |
| 1309 | |
| 1310 | defer func() { |
| 1311 | // If this function ends, it means the context was canceled and this |
| 1312 | // coderd is shutting down. In this case, post a pubsub message to |
| 1313 | // tell other coderd's to resync their entitlements. This is required to |
| 1314 | // make sure things like replica counts are updated in the UI. |
| 1315 | // Ignore the error, as this is just a best effort. If it fails, |
| 1316 | // the system will eventually recover as replicas timeout |
| 1317 | // if their heartbeats stop. The best effort just tries to update the |
| 1318 | // UI faster if it succeeds. |
| 1319 | _ = api.Pubsub.Publish(PubsubEventLicenses, []byte("going away")) |
| 1320 | }() |
| 1321 | for { |
| 1322 | select { |
| 1323 | case <-ctx.Done(): |
| 1324 | return |
| 1325 | default: |
| 1326 | // pass |
| 1327 | } |
| 1328 | if !subscribed { |
| 1329 | cancel, err := api.Pubsub.Subscribe(PubsubEventLicenses, func(_ context.Context, _ []byte) { |
| 1330 | // don't block. If the channel is full, drop the event, as there is a resync |
| 1331 | // scheduled already. |
| 1332 | select { |
| 1333 | case updates <- struct{}{}: |
| 1334 | // pass |
| 1335 | default: |
| 1336 | // pass |
| 1337 | } |
| 1338 | }) |
| 1339 | if err != nil { |
| 1340 | api.Logger.Warn(ctx, "failed to subscribe to license updates", slog.Error(err)) |
| 1341 | select { |
| 1342 | case <-ctx.Done(): |
| 1343 | return |
| 1344 | case <-time.After(b.NextBackOff()): |
| 1345 | } |
| 1346 | continue |
| 1347 | } |
| 1348 | // nolint: revive |
| 1349 | defer cancel() |
| 1350 | subscribed = true |
| 1351 | api.Logger.Debug(ctx, "successfully subscribed to pubsub") |
| 1352 | } |
| 1353 | |
| 1354 | api.Logger.Debug(ctx, "syncing licensed entitlements") |
| 1355 | err := api.updateEntitlements(ctx) |
| 1356 | if err != nil { |
| 1357 | api.Logger.Warn(ctx, "failed to get feature entitlements", slog.Error(err)) |
| 1358 | time.Sleep(b.NextBackOff()) |
| 1359 | continue |
| 1360 | } |
no test coverage detected