mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 16:31:47 +00:00
This PR is a result/followup of the improvements we've made in the [SAMS repo](https://github.com/sourcegraph/sourcegraph-accounts/pull/199) that allows call sites to pass down a context (primarily to indicate deadline, and of course, cancellation if desired) and collects the error returned from `background.Routine`s `Stop` method. Note that I did not adopt returning error from `Stop` method because I realize in monorepo, the more common (and arguably the desired) pattern is to hang on the call of `Start` method until `Stop` is called, so it is meaningless to collect errors from `Start` methods as return values anyway, and doing that would also complicate the design and semantics more than necessary. All usages of the the `background.Routine` and `background.CombinedRoutines` are updated, I DID NOT try to interpret the code logic and make anything better other than fixing compile and test errors. The only file that contains the core change is the [`lib/background/background.go`](https://github.com/sourcegraph/sourcegraph/pull/62136/files#diff-65c3228388620e91f8c22d91c18faac3f985fc67d64b08612df18fa7c04fafcd).
156 lines
5.0 KiB
Go
156 lines
5.0 KiB
Go
package shared
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"net/http"
|
|
"time"
|
|
|
|
smithyhttp "github.com/aws/smithy-go/transport/http"
|
|
"github.com/sourcegraph/log"
|
|
|
|
"github.com/sourcegraph/sourcegraph/internal/authz"
|
|
"github.com/sourcegraph/sourcegraph/internal/authz/providers"
|
|
srp "github.com/sourcegraph/sourcegraph/internal/authz/subrepoperms"
|
|
"github.com/sourcegraph/sourcegraph/internal/codeintel"
|
|
codeintelshared "github.com/sourcegraph/sourcegraph/internal/codeintel/shared"
|
|
"github.com/sourcegraph/sourcegraph/internal/codeintel/shared/lsifuploadstore"
|
|
"github.com/sourcegraph/sourcegraph/internal/codeintel/uploads"
|
|
"github.com/sourcegraph/sourcegraph/internal/conf"
|
|
"github.com/sourcegraph/sourcegraph/internal/conf/conftypes"
|
|
"github.com/sourcegraph/sourcegraph/internal/database"
|
|
connections "github.com/sourcegraph/sourcegraph/internal/database/connections/live"
|
|
"github.com/sourcegraph/sourcegraph/internal/encryption/keyring"
|
|
"github.com/sourcegraph/sourcegraph/internal/goroutine"
|
|
"github.com/sourcegraph/sourcegraph/internal/honey"
|
|
"github.com/sourcegraph/sourcegraph/internal/httpserver"
|
|
"github.com/sourcegraph/sourcegraph/internal/observation"
|
|
"github.com/sourcegraph/sourcegraph/internal/service"
|
|
"github.com/sourcegraph/sourcegraph/internal/uploadstore"
|
|
"github.com/sourcegraph/sourcegraph/lib/errors"
|
|
)
|
|
|
|
const addr = ":3188"
|
|
|
|
func Main(ctx context.Context, observationCtx *observation.Context, ready service.ReadyFunc, config Config) error {
|
|
logger := observationCtx.Logger
|
|
|
|
// Initialize tracing/metrics
|
|
observationCtx = observation.NewContext(logger, observation.Honeycomb(&honey.Dataset{
|
|
Name: "codeintel-worker",
|
|
}))
|
|
|
|
if err := keyring.Init(ctx); err != nil {
|
|
return errors.Wrap(err, "initializing keyring")
|
|
}
|
|
|
|
// Connect to databases
|
|
db := database.NewDB(logger, mustInitializeDB(observationCtx))
|
|
codeIntelDB := mustInitializeCodeIntelDB(observationCtx)
|
|
|
|
// Migrations may take a while, but after they're done we'll immediately
|
|
// spin up a server and can accept traffic. Inform external clients we'll
|
|
// be ready for traffic.
|
|
ready()
|
|
|
|
// Initialize sub-repo permissions client
|
|
authz.DefaultSubRepoPermsChecker = srp.NewSubRepoPermsClient(db.SubRepoPerms())
|
|
|
|
services, err := codeintel.NewServices(codeintel.ServiceDependencies{
|
|
DB: db,
|
|
CodeIntelDB: codeIntelDB,
|
|
ObservationCtx: observationCtx,
|
|
})
|
|
if err != nil {
|
|
return errors.Wrap(err, "creating codeintel services")
|
|
}
|
|
|
|
// Initialize stores
|
|
uploadStore, err := lsifuploadstore.New(ctx, observationCtx, config.LSIFUploadStoreConfig)
|
|
if err != nil {
|
|
return errors.Wrap(err, "creating upload store")
|
|
}
|
|
if err := initializeUploadStore(ctx, uploadStore); err != nil {
|
|
return errors.Wrap(err, "initializing upload store")
|
|
}
|
|
|
|
// Initialize worker
|
|
worker := uploads.NewUploadProcessorJob(
|
|
observationCtx,
|
|
services.UploadsService,
|
|
db,
|
|
uploadStore,
|
|
config.WorkerConcurrency,
|
|
config.WorkerBudget,
|
|
config.WorkerPollInterval,
|
|
config.MaximumRuntimePerJob,
|
|
)
|
|
|
|
// Initialize health server
|
|
server := httpserver.NewFromAddr(addr, &http.Server{
|
|
ReadTimeout: 75 * time.Second,
|
|
WriteTimeout: 10 * time.Minute,
|
|
Handler: httpserver.NewHandler(nil),
|
|
})
|
|
|
|
// Go!
|
|
return goroutine.MonitorBackgroundRoutines(ctx, append(worker, server)...)
|
|
}
|
|
|
|
func mustInitializeDB(observationCtx *observation.Context) *sql.DB {
|
|
dsn := conf.GetServiceConnectionValueAndRestartOnChange(func(serviceConnections conftypes.ServiceConnections) string {
|
|
return serviceConnections.PostgresDSN
|
|
})
|
|
sqlDB, err := connections.EnsureNewFrontendDB(observationCtx, dsn, "precise-code-intel-worker")
|
|
if err != nil {
|
|
log.Scoped("init db").Fatal("Failed to connect to frontend database", log.Error(err))
|
|
}
|
|
|
|
//
|
|
// START FLAILING
|
|
|
|
ctx := context.Background()
|
|
db := database.NewDB(observationCtx.Logger, sqlDB)
|
|
go func() {
|
|
for range time.NewTicker(providers.RefreshInterval(conf.Get())).C {
|
|
allowAccessByDefault, authzProviders, _, _, _ := providers.ProvidersFromConfig(ctx, conf.Get(), db)
|
|
authz.SetProviders(allowAccessByDefault, authzProviders)
|
|
}
|
|
}()
|
|
|
|
// END FLAILING
|
|
//
|
|
|
|
return sqlDB
|
|
}
|
|
|
|
func mustInitializeCodeIntelDB(observationCtx *observation.Context) codeintelshared.CodeIntelDB {
|
|
dsn := conf.GetServiceConnectionValueAndRestartOnChange(func(serviceConnections conftypes.ServiceConnections) string {
|
|
return serviceConnections.CodeIntelPostgresDSN
|
|
})
|
|
db, err := connections.EnsureNewCodeIntelDB(observationCtx, dsn, "precise-code-intel-worker")
|
|
if err != nil {
|
|
log.Scoped("init db").Fatal("Failed to connect to codeintel database", log.Error(err))
|
|
}
|
|
|
|
return codeintelshared.NewCodeIntelDB(observationCtx.Logger, db)
|
|
}
|
|
|
|
func initializeUploadStore(ctx context.Context, uploadStore uploadstore.Store) error {
|
|
for {
|
|
if err := uploadStore.Init(ctx); err == nil || !isRequestError(err) {
|
|
return err
|
|
}
|
|
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
case <-time.After(250 * time.Millisecond):
|
|
}
|
|
}
|
|
}
|
|
|
|
func isRequestError(err error) bool {
|
|
return errors.HasType(err, &smithyhttp.RequestSendError{})
|
|
}
|