| 28 | const staleTerraformPluginRetention = 30 * 24 * time.Hour |
| 29 | |
| 30 | func (s *server) setupContexts(parent context.Context, canceledOrComplete <-chan struct{}) ( |
| 31 | ctx context.Context, cancel func(), killCtx context.Context, kill func(), |
| 32 | ) { |
| 33 | // Create a context for graceful cancellation bound to the session |
| 34 | // context. This ensures that we will perform graceful cancellation |
| 35 | // even on connection loss. |
| 36 | ctx, cancel = context.WithCancel(parent) |
| 37 | |
| 38 | // Create a separate context for forceful cancellation not tied to |
| 39 | // the stream so that we can control when to terminate the process. |
| 40 | killCtx, kill = context.WithCancel(context.Background()) |
| 41 | |
| 42 | // Ensure processes are eventually cleaned up on graceful |
| 43 | // cancellation or disconnect. |
| 44 | go func() { |
| 45 | <-ctx.Done() |
| 46 | s.logger.Debug(ctx, "graceful context done") |
| 47 | |
| 48 | // TODO(mafredri): We should track this provision request as |
| 49 | // part of graceful server shutdown procedure. Waiting on a |
| 50 | // process here should delay provisioner/coder shutdown. |
| 51 | t := time.NewTimer(s.exitTimeout) |
| 52 | defer t.Stop() |
| 53 | select { |
| 54 | case <-t.C: |
| 55 | s.logger.Debug(ctx, "exit timeout hit") |
| 56 | kill() |
| 57 | case <-killCtx.Done(): |
| 58 | s.logger.Debug(ctx, "kill context done") |
| 59 | } |
| 60 | }() |
| 61 | |
| 62 | // Process cancel |
| 63 | go func() { |
| 64 | <-canceledOrComplete |
| 65 | s.logger.Debug(ctx, "canceledOrComplete closed") |
| 66 | cancel() |
| 67 | }() |
| 68 | return ctx, cancel, killCtx, kill |
| 69 | } |
| 70 | |
| 71 | func (s *server) Init( |
| 72 | sess *provisionersdk.Session, request *provisionersdk.InitRequest, canceledOrComplete <-chan struct{}, |