internal/callback/callback.go (90 lines of code) (raw):

// Package callback provides functionality for sending operation status callbacks to GitLab. // It implements mechanisms for reporting success or failure of operations (particularly indexing) // back to GitLab via internal API calls. The package handles constructing appropriate payloads, // including repository statistics when needed, and manages the HTTP communication with configurable // timeouts and authentication. package callback import ( "context" "fmt" "log/slog" "net/http" "time" internal_api "gitlab.com/gitlab-org/gitlab-zoekt-indexer/internal/api" "gitlab.com/gitlab-org/gitlab-zoekt-indexer/internal/disk_stats" ) type CallbackFunc struct { OnSuccess func(CallbackParams) OnFailure func(CallbackParams, error) } type CallbackAPI struct { GitlabURL string NodeUUID string Secret []byte Client *http.Client } type CallbackParams struct { Name string `json:"name"` RailsPayload any `json:"payload"` } // AdditionalPayload might get new fields in the future when there will be new callback actions. Right now we add only RepoStats for the index action type AdditionalPayload struct { RepoStats *disk_stats.RepoStats `json:"repo_stats,omitempty"` } type CallbackBody struct { Name string `json:"name"` Success bool `json:"success"` Payload any `json:"payload"` AdditionalPayload *AdditionalPayload `json:"additional_payload,omitempty"` Error string `json:"error,omitempty"` } const ( apiPath = "callback" timeout = time.Minute ) func NewCallbackAPI(gitlabURL, nodeUUID string, secret []byte, client *http.Client) (CallbackAPI, error) { return CallbackAPI{ GitlabURL: gitlabURL, NodeUUID: nodeUUID, Secret: secret, Client: client, }, nil } func (c CallbackAPI) SendSuccess(ctx context.Context, callbackParams CallbackParams, indexDir string, repoID uint32) { payload := buildPayload(callbackParams, indexDir, repoID, true) c.sendCallback(ctx, payload) } func (c CallbackAPI) SendFailure(ctx context.Context, callbackParams CallbackParams, indexDir string, repoID uint32, failureReason error) { payload := buildPayload(callbackParams, indexDir, repoID, false) payload.Error = failureReason.Error() c.sendCallback(ctx, payload) } func buildPayload(callbackParams CallbackParams, indexDir string, repoID uint32, success bool) CallbackBody { railsPayload := callbackParams.RailsPayload // Rails payload var additionalPayload AdditionalPayload if callbackParams.Name == "index" { repoStats := disk_stats.GetFileSizeAndCount(indexDir, fmt.Sprintf("%d_*.zoekt", repoID)) additionalPayload.RepoStats = &repoStats } return CallbackBody{ Name: callbackParams.Name, Success: success, Payload: railsPayload, AdditionalPayload: &additionalPayload, } } func (c CallbackAPI) sendCallback(ctx context.Context, payload CallbackBody) { apiParams := internal_api.InternalAPIRequestParams{ Path: apiPath, BodyParams: payload, GitlabURL: c.GitlabURL, NodeUUID: c.NodeUUID, Secret: c.Secret, } ctx, cancel := context.WithTimeout(ctx, timeout) defer cancel() req, err := internal_api.NewRequest(ctx, apiParams) slog.Debug("sending callback request", "payload", payload) if err != nil { slog.Error("error while creating a new request", "err", err) return } _, errRequest := c.Client.Do(req) //nolint:bodyclose if errRequest != nil { slog.Error("error while creating a new request", "err", errRequest) } }