Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into unused_assets
Browse files Browse the repository at this point in the history
  • Loading branch information
k-anshul committed Feb 4, 2025
2 parents 2036143 + 310feff commit 0b6532b
Show file tree
Hide file tree
Showing 127 changed files with 1,928 additions and 1,069 deletions.
39 changes: 34 additions & 5 deletions admin/billing.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,28 @@ func (s *Service) InitOrganizationBilling(ctx context.Context, org *database.Org
if err != nil {
return nil, err
}
s.Logger.Info("created payment customer", zap.String("org_id", org.ID), zap.String("org_name", org.Name), zap.String("payment_customer_id", pc.ID))
s.Logger.Info("created payment customer",
zap.String("org_id", org.ID),
zap.String("org_name", org.Name),
zap.String("payment_customer_id", pc.ID),
zap.String("user_email", org.BillingEmail),
)

org.PaymentCustomerID = pc.ID

// create billing customer
bc, err := s.Biller.CreateCustomer(ctx, org, billing.PaymentProviderStripe)
if err != nil {
return nil, err
}
s.Logger.Info("created billing customer", zap.String("org", org.Name), zap.String("billing_customer_id", bc.ID))
s.Logger.Info("created billing customer",
zap.String("org", org.Name),
zap.String("org_id", org.ID),
zap.String("billing_customer_id", bc.ID),
zap.String("payment_customer_id", pc.ID),
zap.String("user_email", org.BillingEmail),
)

org.BillingCustomerID = bc.ID

org, err = s.DB.UpdateOrganization(ctx, org.ID, &database.UpdateOrganizationOptions{
Expand Down Expand Up @@ -90,7 +103,12 @@ func (s *Service) RepairOrganizationBilling(ctx context.Context, org *database.O
if err != nil {
return nil, nil, fmt.Errorf("failed to create payment customer: %w", err)
}
s.Logger.Info("created payment customer", zap.String("org_id", org.ID), zap.String("org_name", org.Name), zap.String("payment_customer_id", pc.ID))
s.Logger.Info("created payment customer",
zap.String("org_id", org.ID),
zap.String("org_name", org.Name),
zap.String("payment_customer_id", pc.ID),
zap.String("user_email", pc.Email),
)
} else {
return nil, nil, fmt.Errorf("error finding payment customer: %w", err)
}
Expand All @@ -110,7 +128,13 @@ func (s *Service) RepairOrganizationBilling(ctx context.Context, org *database.O
if err != nil {
return nil, nil, fmt.Errorf("failed to create billing customer: %w", err)
}
s.Logger.Info("created billing customer", zap.String("org_id", org.ID), zap.String("org_name", org.Name), zap.String("billing_customer_id", bc.ID))
s.Logger.Info("created billing customer",
zap.String("org_id", org.ID),
zap.String("org_name", org.Name),
zap.String("billing_customer_id", bc.Email),
zap.String("payment_customer_id", org.PaymentCustomerID),
zap.String("user_email", org.BillingEmail),
)
org.BillingCustomerID = bc.ID
} else if bc.PaymentProviderID == "" {
// update payment customer id in billing system
Expand Down Expand Up @@ -244,7 +268,12 @@ func (s *Service) StartTrial(ctx context.Context, org *database.Organization) (*
return org, sub, nil
}

s.Logger.Named("billing").Info("started trial for organization", zap.String("org_name", org.Name), zap.String("org_id", org.ID), zap.String("trial_end_date", sub.TrialEndDate.String()))
s.Logger.Named("billing").Info("started trial for organization",
zap.String("org_name", org.Name),
zap.String("org_id", org.ID),
zap.String("trial_end_date", sub.TrialEndDate.String()),
zap.String("email", *org.CreatedByUserID),
)

org, err = s.DB.UpdateOrganization(ctx, org.ID, &database.UpdateOrganizationOptions{
Name: org.Name,
Expand Down
1 change: 1 addition & 0 deletions admin/database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ type DB interface {
InsertProject(ctx context.Context, opts *InsertProjectOptions) (*Project, error)
DeleteProject(ctx context.Context, id string) error
UpdateProject(ctx context.Context, id string, opts *UpdateProjectOptions) (*Project, error)
CountProjectsForOrganization(ctx context.Context, orgID string) (int, error)
CountProjectsQuotaUsage(ctx context.Context, orgID string) (*ProjectsQuotaUsage, error)
FindProjectWhitelistedDomain(ctx context.Context, projectID, domain string) (*ProjectWhitelistedDomain, error)
FindProjectWhitelistedDomainForProjectWithJoinedRoleNames(ctx context.Context, projectID string) ([]*ProjectWhitelistedDomainWithJoinedRoleNames, error)
Expand Down
21 changes: 15 additions & 6 deletions admin/database/postgres/postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,15 @@ func (c *connection) FindOrganizationByName(ctx context.Context, name string) (*
return res, nil
}

func (c *connection) CountProjectsForOrganization(ctx context.Context, orgID string) (int, error) {
var count int
err := c.getDB(ctx).SelectContext(ctx, &count, "SELECT COUNT(*) FROM projects WHERE org_id=$1", orgID)
if err != nil {
return 0, parseErr("projects", err)
}
return count, nil
}

func (c *connection) FindOrganizationByCustomDomain(ctx context.Context, domain string) (*database.Organization, error) {
res := &database.Organization{}
err := c.getDB(ctx).QueryRowxContext(ctx, "SELECT * FROM orgs WHERE lower(custom_domain)=lower($1)", domain).StructScan(res)
Expand Down Expand Up @@ -2132,14 +2141,14 @@ func (c *connection) FindProjectVariables(ctx context.Context, projectID string,
// Also include variables that are not environment specific and not set for the given environment
q += `
AND (
p.environment = $2
p.environment = $2
OR (
p.environment = ''
p.environment = ''
AND NOT EXISTS (
SELECT 1
FROM project_variables p2
WHERE p2.project_id = p.project_id
AND p2.environment = $2
SELECT 1
FROM project_variables p2
WHERE p2.project_id = p.project_id
AND p2.environment = $2
AND lower(p2.name) = lower(p.name)
)
)
Expand Down
2 changes: 1 addition & 1 deletion admin/jobs/jobs.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type Client interface {
PaymentFailed(ctx context.Context, billingCustomerID, invoiceID, invoiceNumber, invoiceURL, amount, currency string, dueDate, failedAt time.Time) (*InsertResult, error)
PaymentSuccess(ctx context.Context, billingCustomerID, invoiceID string) (*InsertResult, error)

// org related joba
// org related jobs
InitOrgBilling(ctx context.Context, orgID string) (*InsertResult, error)
RepairOrgBilling(ctx context.Context, orgID string) (*InsertResult, error) // biller is just used for deduplication
StartOrgTrial(ctx context.Context, orgID string) (*InsertResult, error)
Expand Down
21 changes: 7 additions & 14 deletions admin/jobs/river/org_jobs.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package river
import (
"context"
"errors"
"fmt"

"github.com/rilldata/rill/admin"
"github.com/rilldata/rill/admin/database"
Expand Down Expand Up @@ -31,24 +32,21 @@ func (w *InitOrgBillingWorker) Work(ctx context.Context, job *river.Job[InitOrgB
// org got deleted, ignore
return nil
}
w.logger.Error("failed to find organization", zap.String("org_id", job.Args.OrgID), zap.Error(err))
return err
return fmt.Errorf("failed to find organization %s: %w", job.Args.OrgID, err)
}

if job.Attempt > 1 {
// rare case but if its retried, we should repair the billing as it might be in some inconsistent state
_, _, err = w.admin.RepairOrganizationBilling(ctx, org, false)
if err != nil {
w.logger.Error("failed to init billing for organization", zap.String("org_name", org.Name), zap.String("org_id", org.ID), zap.Error(err))
return err
return fmt.Errorf("failed to repair billing for organization %s: %w", org.Name, err)
}
return nil
}

_, err = w.admin.InitOrganizationBilling(ctx, org)
if err != nil {
w.logger.Error("failed to init billing for organization", zap.String("org_name", org.Name), zap.String("org_id", org.ID), zap.Error(err))
return err
return fmt.Errorf("failed to init billing for organization %s: %w", org.Name, err)
}
return nil
}
Expand All @@ -73,14 +71,12 @@ func (w *RepairOrgBillingWorker) Work(ctx context.Context, job *river.Job[Repair
// org got deleted, ignore
return nil
}
w.logger.Error("failed to find organization", zap.String("org_id", job.Args.OrgID), zap.Error(err))
return err
return fmt.Errorf("failed to find organization %s: %w", job.Args.OrgID, err)
}

_, _, err = w.admin.RepairOrganizationBilling(ctx, org, true)
if err != nil {
w.logger.Error("failed to repair billing for organization", zap.String("org_name", org.Name), zap.String("org_id", org.ID), zap.Error(err))
return err
return fmt.Errorf("failed to repair billing for organization %s: %w", org.Name, err)
}
return nil
}
Expand Down Expand Up @@ -110,10 +106,7 @@ func (w *StartTrialWorker) Work(ctx context.Context, job *river.Job[StartTrialAr

trialOrg, sub, err := w.admin.StartTrial(ctx, org)
if err != nil {
if job.Attempt >= job.MaxAttempts {
w.logger.Error("failed to start trial for organization", zap.String("org_name", org.Name), zap.String("org_id", org.ID), zap.Error(err))
}
return err
return fmt.Errorf("failed to start trial for organization %s: %w", org.Name, err)
}

// send trial started email
Expand Down
9 changes: 8 additions & 1 deletion admin/jobs/river/subscription_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,13 @@ func (w *SubscriptionCancellationCheckWorker) subscriptionCancellationCheck(ctx
// hibernate projects
limit := 10
afterProjectName := ""
projectCount := 0
for {
projs, err := w.admin.DB.FindProjectsForOrganization(ctx, org.ID, afterProjectName, limit)
if err != nil {
return err
}
projectCount += len(projs)

for _, proj := range projs {
_, err = w.admin.HibernateProject(ctx, proj)
Expand All @@ -118,7 +120,12 @@ func (w *SubscriptionCancellationCheckWorker) subscriptionCancellationCheck(ctx
w.logger.Error("failed to send subscription ended email", zap.String("org_id", org.ID), zap.String("org_name", org.Name), zap.String("billing_email", org.BillingEmail), zap.Error(err))
}

w.logger.Warn("projects hibernated due to subscription cancellation", zap.String("org_id", org.ID), zap.String("org_name", org.Name))
w.logger.Warn("projects hibernated due to subscription cancellation",
zap.String("org_id", org.ID),
zap.String("org_name", org.Name),
zap.Int("count_of_projects", projectCount),
zap.String("user_email", org.BillingEmail),
)

// mark the billing issue as processed
err = w.admin.DB.UpdateBillingIssueOverdueAsProcessed(ctx, issue.ID)
Expand Down
21 changes: 20 additions & 1 deletion admin/jobs/river/trial_checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,26 @@ func (w *TrialEndingSoonWorker) trialEndingSoon(ctx context.Context) error {
return fmt.Errorf("failed to find organization: %w", err)
}

w.logger.Warn("trial ending soon", zap.String("org_id", org.ID), zap.String("org_name", org.Name), zap.Time("trial_end_date", m.EndDate))
// remaining days in the trial period
daysRemaining := int(m.EndDate.Sub(time.Now().UTC()).Hours() / 24)
if daysRemaining < 0 {
daysRemaining = 0
}

// number of projects for the org
projects, err := w.admin.DB.CountProjectsForOrganization(ctx, org.ID)
if err != nil {
return fmt.Errorf("failed to count projects for org %q: %w", org.Name, err)
}

w.logger.Warn("trial ending soon",
zap.String("org_id", org.ID),
zap.String("org_name", org.Name),
zap.Time("trial_end_date", m.EndDate),
zap.String("user_email", org.BillingEmail),
zap.Int("count_of_projects", projects),
zap.Int("count_of_days_remaining", daysRemaining),
)

err = w.admin.Email.SendTrialEndingSoon(&email.TrialEndingSoon{
ToEmail: org.BillingEmail,
Expand Down
13 changes: 11 additions & 2 deletions admin/projects.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,17 @@ func (s *Service) CreateProject(ctx context.Context, org *database.Organization,
return nil, multierr.Combine(err, err2, err3)
}

// Log project creation
s.Logger.Info("created project", zap.String("id", proj.ID), zap.String("name", proj.Name), zap.String("org", org.Name), zap.Any("user_id", opts.CreatedByUserID))
user, err := s.DB.FindUser(ctx, *proj.CreatedByUserID)
if err != nil {
return nil, err
}

plan, err := s.Biller.GetDefaultPlan(ctx)
if err != nil {
return nil, err
}

s.Logger.Info("created project", zap.String("id", proj.ID), zap.String("name", proj.Name), zap.String("org", org.Name), zap.Any("user_id", opts.CreatedByUserID), zap.String("user_email", user.Email), zap.String("billing_plan", plan.Name))

return res, nil
}
Expand Down
23 changes: 21 additions & 2 deletions admin/server/billing.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,12 @@ func (s *Server) UpdateBillingSubscription(ctx context.Context, req *adminv1.Upd
return nil, err
}
planChange = true
s.logger.Named("billing").Info("new subscription created", zap.String("org_id", org.ID), zap.String("org_name", org.Name), zap.String("plan_id", sub.Plan.ID), zap.String("plan_name", sub.Plan.Name))
s.logger.Named("billing").Info("new subscription created",
zap.String("org_id", org.ID),
zap.String("org_name", org.Name),
zap.String("plan_id", sub.Plan.ID),
zap.String("plan_name", sub.Plan.Name),
)
} else {
// schedule plan change
oldPlan := sub.Plan
Expand All @@ -183,7 +188,14 @@ func (s *Server) UpdateBillingSubscription(ctx context.Context, req *adminv1.Upd
return nil, err
}
planChange = true
s.logger.Named("billing").Info("plan changed", zap.String("org_id", org.ID), zap.String("org_name", org.Name), zap.String("old_plan_id", oldPlan.ID), zap.String("old_plan_name", oldPlan.Name), zap.String("new_plan_id", sub.Plan.ID), zap.String("new_plan_name", sub.Plan.Name))
s.logger.Named("billing").Info("plan changed",
zap.String("org_id", org.ID),
zap.String("org_name", org.Name),
zap.String("old_plan_id", oldPlan.ID),
zap.String("old_plan_name", oldPlan.Name),
zap.String("new_plan_id", sub.Plan.ID),
zap.String("new_plan_name", sub.Plan.Name),
)
}
}

Expand All @@ -196,6 +208,13 @@ func (s *Server) UpdateBillingSubscription(ctx context.Context, req *adminv1.Upd
// send plan changed email

if plan.PlanType == billing.TeamPlanType {
s.logger.Named("billing").Info("upgraded to team plan",
zap.String("org_id", org.ID),
zap.String("org_name", org.Name),
zap.String("plan_id", sub.Plan.ID),
zap.String("plan_name", sub.Plan.Name),
)

// special handling for team plan to send custom email
err = s.admin.Email.SendTeamPlanStarted(&email.TeamPlan{
ToEmail: org.BillingEmail,
Expand Down
6 changes: 3 additions & 3 deletions admin/worker/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package worker

import (
"context"
"errors"
"fmt"
"net/http"
"time"
Expand Down Expand Up @@ -107,7 +108,7 @@ func (w *Worker) RunJob(ctx context.Context, name string) error {
func (w *Worker) schedule(ctx context.Context, name string, fn func(context.Context) error, every time.Duration) error {
for {
err := w.runJob(ctx, name, fn)
if err != nil {
if err != nil && !errors.Is(err, context.Canceled) {
w.logger.Error("Failed to run the job", zap.String("job_name", name), zap.Error(err))
}
select {
Expand All @@ -133,7 +134,7 @@ func (w *Worker) scheduleCron(ctx context.Context, name string, fn func(context.
return nil
case <-time.After(waitDuration):
err := w.runJob(ctx, name, fn)
if err != nil {
if err != nil && !errors.Is(err, context.Canceled) {
w.logger.Error("Failed to run the cronjob", zap.String("cronjob_name", name), zap.Error(err))
}
}
Expand All @@ -152,7 +153,6 @@ func (w *Worker) runJob(ctx context.Context, name string, fn func(context.Contex
err := fn(ctx)
jobLatencyHistogram.Record(ctx, time.Since(start).Milliseconds(), metric.WithAttributes(attribute.String("name", name), attribute.Bool("failed", err != nil)))
if err != nil {
w.logger.Error("job failed", zap.String("name", name), zap.Error(err), zap.Duration("duration", time.Since(start)), observability.ZapCtx(ctx))
return err
}
w.logger.Info("job completed", zap.String("name", name), zap.Duration("duration", time.Since(start)), observability.ZapCtx(ctx))
Expand Down
Loading

0 comments on commit 0b6532b

Please sign in to comment.