From 7ab8517a93943c5ac6a6344f7acd3489ee2f9450 Mon Sep 17 00:00:00 2001 From: yoan <536464346@qq.com> Date: Wed, 23 Oct 2024 17:32:35 +0800 Subject: [PATCH] Handle concurrency issues in a simple way. --- internal/applicant/applicant.go | 6 +++++ internal/repository/acme_account.go | 36 ++++++++++++++++++++++------- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/internal/applicant/applicant.go b/internal/applicant/applicant.go index a901be77..17e97cb5 100644 --- a/internal/applicant/applicant.go +++ b/internal/applicant/applicant.go @@ -318,6 +318,12 @@ func getReg(client *lego.Client, sslProvider *SSLProviderConfig, user *ApplyUser repo := getAcmeAccountRepository() + resp, err := repo.GetByCAAndEmail(sslProvider.Provider, user.GetEmail()) + if err == nil { + user.key = resp.Key + return resp.Resource, nil + } + if err := repo.Save(sslProvider.Provider, user.GetEmail(), user.getPrivateKeyString(), reg); err != nil { return nil, fmt.Errorf("failed to save registration: %w", err) } diff --git a/internal/repository/acme_account.go b/internal/repository/acme_account.go index 07da5b36..9f7e6d21 100644 --- a/internal/repository/acme_account.go +++ b/internal/repository/acme_account.go @@ -1,11 +1,14 @@ package repository import ( + "fmt" + "github.com/go-acme/lego/v4/registration" "github.com/pocketbase/dbx" "github.com/pocketbase/pocketbase/models" "github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/utils/app" + "golang.org/x/sync/singleflight" ) type AcmeAccountRepository struct{} @@ -14,25 +17,42 @@ func NewAcmeAccountRepository() *AcmeAccountRepository { return &AcmeAccountRepository{} } +var g singleflight.Group + func (r *AcmeAccountRepository) GetByCAAndEmail(ca, email string) (*domain.AcmeAccount, error) { - resp, err := app.GetApp().Dao().FindFirstRecordByFilter("acme_accounts", "ca={:ca} && email={:email}", dbx.Params{"ca": ca, "email": email}) + resp, err, _ := g.Do(fmt.Sprintf("acme_account_%s_%s", ca, email), func() (interface{}, error) { + resp, err := app.GetApp().Dao().FindFirstRecordByFilter("acme_accounts", "ca={:ca} && email={:email}", dbx.Params{"ca": ca, "email": email}) + if err != nil { + return nil, err + } + return resp, nil + }) if err != nil { return nil, err } + if resp == nil { + return nil, fmt.Errorf("acme account not found") + } + + record, ok := resp.(*models.Record) + if !ok { + return nil, fmt.Errorf("acme account not found") + } + resource := ®istration.Resource{} - if err := resp.UnmarshalJSONField("resource", resource); err != nil { + if err := record.UnmarshalJSONField("resource", resource); err != nil { return nil, err } return &domain.AcmeAccount{ - Id: resp.GetString("id"), - Ca: resp.GetString("ca"), - Email: resp.GetString("email"), - Key: resp.GetString("key"), + Id: record.GetString("id"), + Ca: record.GetString("ca"), + Email: record.GetString("email"), + Key: record.GetString("key"), Resource: resource, - Created: resp.GetTime("created"), - Updated: resp.GetTime("updated"), + Created: record.GetTime("created"), + Updated: record.GetTime("updated"), }, nil }