Handle concurrency issues in a simple way.

This commit is contained in:
yoan 2024-10-23 17:32:35 +08:00
parent 1dca6ecf8d
commit 7ab8517a93
2 changed files with 34 additions and 8 deletions

View File

@ -318,6 +318,12 @@ func getReg(client *lego.Client, sslProvider *SSLProviderConfig, user *ApplyUser
repo := getAcmeAccountRepository() 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 { if err := repo.Save(sslProvider.Provider, user.GetEmail(), user.getPrivateKeyString(), reg); err != nil {
return nil, fmt.Errorf("failed to save registration: %w", err) return nil, fmt.Errorf("failed to save registration: %w", err)
} }

View File

@ -1,11 +1,14 @@
package repository package repository
import ( import (
"fmt"
"github.com/go-acme/lego/v4/registration" "github.com/go-acme/lego/v4/registration"
"github.com/pocketbase/dbx" "github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/models" "github.com/pocketbase/pocketbase/models"
"github.com/usual2970/certimate/internal/domain" "github.com/usual2970/certimate/internal/domain"
"github.com/usual2970/certimate/internal/utils/app" "github.com/usual2970/certimate/internal/utils/app"
"golang.org/x/sync/singleflight"
) )
type AcmeAccountRepository struct{} type AcmeAccountRepository struct{}
@ -14,25 +17,42 @@ func NewAcmeAccountRepository() *AcmeAccountRepository {
return &AcmeAccountRepository{} return &AcmeAccountRepository{}
} }
var g singleflight.Group
func (r *AcmeAccountRepository) GetByCAAndEmail(ca, email string) (*domain.AcmeAccount, error) { 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 { if err != nil {
return nil, err 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 := &registration.Resource{} resource := &registration.Resource{}
if err := resp.UnmarshalJSONField("resource", resource); err != nil { if err := record.UnmarshalJSONField("resource", resource); err != nil {
return nil, err return nil, err
} }
return &domain.AcmeAccount{ return &domain.AcmeAccount{
Id: resp.GetString("id"), Id: record.GetString("id"),
Ca: resp.GetString("ca"), Ca: record.GetString("ca"),
Email: resp.GetString("email"), Email: record.GetString("email"),
Key: resp.GetString("key"), Key: record.GetString("key"),
Resource: resource, Resource: resource,
Created: resp.GetTime("created"), Created: record.GetTime("created"),
Updated: resp.GetTime("updated"), Updated: record.GetTime("updated"),
}, nil }, nil
} }