Refactor: improve code quality and worker flow
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"moku-backend/internal/jobs"
|
||||
"moku-backend/internal/posixproj"
|
||||
)
|
||||
|
||||
func (service *Service) enqueueBootstrapStructureMaterialization(
|
||||
ctx context.Context,
|
||||
installation *InstallationRecord,
|
||||
) error {
|
||||
if installation == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
jobStore := jobs.NewStore(service.db)
|
||||
if _, err := jobStore.Enqueue(ctx, jobs.EnqueueInput{
|
||||
Kind: jobs.KindBootstrapStructureMaterialize,
|
||||
Payload: jobs.BootstrapStructureMaterializePayload{
|
||||
InstallationID: installation.ID,
|
||||
},
|
||||
}); err != nil {
|
||||
failure := fmt.Sprintf("enqueue bootstrap materialization job: %v", err)
|
||||
if markErr := service.markBootstrapMaterializationFailed(ctx, installation.ID, failure); markErr != nil {
|
||||
return errors.Join(err, markErr)
|
||||
}
|
||||
|
||||
// The relational bootstrap write already committed successfully, so keep the
|
||||
// response successful and surface the enqueue problem via materialization state.
|
||||
installation.MaterializationStatus = materializationFailed
|
||||
installation.MaterializationError = &failure
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (service *Service) ProcessBootstrapStructureMaterialization(ctx context.Context, installationID string) error {
|
||||
trimmedInstallationID := strings.TrimSpace(installationID)
|
||||
if trimmedInstallationID == "" {
|
||||
return ErrInstallationNotConfigured
|
||||
}
|
||||
|
||||
installation, err := service.GetInstallation(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if installation == nil || installation.ID != trimmedInstallationID {
|
||||
return ErrInstallationNotConfigured
|
||||
}
|
||||
|
||||
if err := service.markBootstrapMaterializationRunning(ctx, trimmedInstallationID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := service.materializeBootstrapStructure(ctx, *installation); err != nil {
|
||||
failure := strings.TrimSpace(err.Error())
|
||||
if failure == "" {
|
||||
failure = "bootstrap materialization failed"
|
||||
}
|
||||
|
||||
if markErr := service.markBootstrapMaterializationFailed(ctx, trimmedInstallationID, failure); markErr != nil {
|
||||
return errors.Join(err, markErr)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
return service.markBootstrapMaterializationSucceeded(ctx, trimmedInstallationID)
|
||||
}
|
||||
|
||||
func (service *Service) materializeBootstrapStructure(ctx context.Context, installation InstallationRecord) error {
|
||||
admin, err := service.GetAdmin(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if admin == nil {
|
||||
return ErrAdminNotConfigured
|
||||
}
|
||||
|
||||
organization, err := service.loadPrimaryOrganization(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if organization == nil {
|
||||
return ErrBootstrapStructureMissing
|
||||
}
|
||||
|
||||
department, err := service.loadPrimaryDepartment(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if department == nil {
|
||||
return ErrBootstrapStructureMissing
|
||||
}
|
||||
|
||||
team, err := service.loadPrimaryTeam(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if team == nil {
|
||||
return ErrBootstrapStructureMissing
|
||||
}
|
||||
|
||||
project, err := service.loadPrimaryProject(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if project == nil {
|
||||
return ErrBootstrapStructureMissing
|
||||
}
|
||||
|
||||
if err := service.ensureBootstrapPOSIXSkeleton(
|
||||
installation,
|
||||
AdminSummary{ID: admin.ID, Email: admin.Email, DisplayName: admin.DisplayName},
|
||||
namedRecord{ID: organization.ID, Name: organization.Name, Slug: organization.Slug},
|
||||
namedRecord{ID: department.ID, Name: department.Name, Slug: department.Slug},
|
||||
namedRecord{ID: team.ID, Name: team.Name, Slug: team.Slug},
|
||||
namedRecord{ID: project.ID, Name: project.Name, Slug: project.Slug},
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return service.rebuildProjection(ctx)
|
||||
}
|
||||
|
||||
func (service *Service) rebuildProjection(ctx context.Context) error {
|
||||
if err := posixproj.NewProjector(service.db, service.posixRoot).Rebuild(ctx); err != nil {
|
||||
return fmt.Errorf("rebuild POSIX projection: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (service *Service) markBootstrapMaterializationRunning(ctx context.Context, installationID string) error {
|
||||
_, err := service.db.Pool.Exec(ctx, `
|
||||
UPDATE installations
|
||||
SET
|
||||
materialization_status = 'running'::bootstrap_materialization_status,
|
||||
materialization_error = NULL,
|
||||
materialization_started_at = NOW(),
|
||||
materialization_finished_at = NULL,
|
||||
updated_at = NOW()
|
||||
WHERE id = $1::uuid;
|
||||
`, strings.TrimSpace(installationID))
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (service *Service) markBootstrapMaterializationSucceeded(ctx context.Context, installationID string) error {
|
||||
_, err := service.db.Pool.Exec(ctx, `
|
||||
UPDATE installations
|
||||
SET
|
||||
materialization_status = 'succeeded'::bootstrap_materialization_status,
|
||||
materialization_error = NULL,
|
||||
materialization_finished_at = NOW(),
|
||||
updated_at = NOW()
|
||||
WHERE id = $1::uuid;
|
||||
`, strings.TrimSpace(installationID))
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (service *Service) markBootstrapMaterializationFailed(ctx context.Context, installationID, failure string) error {
|
||||
_, err := service.db.Pool.Exec(ctx, `
|
||||
UPDATE installations
|
||||
SET
|
||||
materialization_status = 'failed'::bootstrap_materialization_status,
|
||||
materialization_error = $2,
|
||||
materialization_finished_at = NOW(),
|
||||
updated_at = NOW()
|
||||
WHERE id = $1::uuid;
|
||||
`, strings.TrimSpace(installationID), strings.TrimSpace(failure))
|
||||
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user