()
| 1844 | } |
| 1845 | |
| 1846 | func (r *basePoolManager) Start() error { |
| 1847 | r.SetPoolRunningState(false, "pool manager is starting up") |
| 1848 | initializeEntity := make(chan struct{}, 1) |
| 1849 | go func() { |
| 1850 | // At this point, we just mark instances in `creating` and `deleting` as `pending_delete` |
| 1851 | // These instances were interrupted while transitioning, so they are in a state we need |
| 1852 | // to recover from. The call to DeleteRunner() will potentially remove them from github |
| 1853 | // if using JIT, and mark them for deleting. The actual deletion will happen only after |
| 1854 | // tools are fetched and the loops start. |
| 1855 | slog.InfoContext(r.ctx, "cleaning up instances that were interrupted in flight") |
| 1856 | if err := r.cleanupRunnersInterruptedInFlight(); err != nil { |
| 1857 | slog.ErrorContext(r.ctx, "startup runner cleanup failed", "error", err) |
| 1858 | } |
| 1859 | |
| 1860 | slog.Info("running initial tool update") |
| 1861 | for { |
| 1862 | slog.DebugContext(r.ctx, "waiting for tools to be available") |
| 1863 | hasTools, stopped := r.waitForToolsOrCancel() |
| 1864 | if stopped { |
| 1865 | return |
| 1866 | } |
| 1867 | if hasTools { |
| 1868 | break |
| 1869 | } |
| 1870 | } |
| 1871 | if err := r.updateTools(); err != nil { |
| 1872 | slog.With(slog.Any("error", err)).Error("failed to update tools") |
| 1873 | } |
| 1874 | initializeEntity <- struct{}{} |
| 1875 | }() |
| 1876 | |
| 1877 | go r.runWatcher() |
| 1878 | go func() { |
| 1879 | select { |
| 1880 | case <-r.quit: |
| 1881 | return |
| 1882 | case <-r.ctx.Done(): |
| 1883 | return |
| 1884 | case <-initializeEntity: |
| 1885 | } |
| 1886 | defer close(initializeEntity) |
| 1887 | go r.startLoopForFunction(r.runnerCleanup, common.PoolReapTimeoutInterval, "timeout_reaper", false) |
| 1888 | go r.startLoopForFunction(r.scaleDown, common.PoolScaleDownInterval, "scale_down", false) |
| 1889 | // always run the delete pending instances routine. This way we can still remove existing runners, even if the pool is not running. |
| 1890 | go r.startLoopForFunction(r.deletePendingInstances, common.PoolConsilitationInterval, "consolidate[delete_pending]", true) |
| 1891 | go r.startLoopForFunction(r.addPendingInstances, common.PoolConsilitationInterval, "consolidate[add_pending]", false) |
| 1892 | go r.startLoopForFunction(r.ensureMinIdleRunners, common.PoolConsilitationInterval, "consolidate[ensure_min_idle]", false) |
| 1893 | go r.startLoopForFunction(r.retryFailedInstances, common.PoolConsilitationInterval, "consolidate[retry_failed]", false) |
| 1894 | go r.startLoopForFunction(r.updateTools, common.PoolToolUpdateInterval, "update_tools", true) |
| 1895 | go r.startLoopForFunction(r.consumeQueuedJobs, common.PoolConsilitationInterval, "job_queue_consumer", false) |
| 1896 | go r.startLoopForFunction(r.reconcileStaleJobs, common.PoolStaleJobReconcileInterval, "stale_job_reconciler", false) |
| 1897 | }() |
| 1898 | return nil |
| 1899 | } |
| 1900 | |
| 1901 | func (r *basePoolManager) Stop() error { |
| 1902 | close(r.quit) |
nothing calls this directly
no test coverage detected