-
Notifications
You must be signed in to change notification settings - Fork 2k
[CRE] OrgResolver with DB-backed cache #23485
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "chainlink": minor | ||
| --- | ||
|
|
||
| #added Durable caching of OrgResolver owner->orgID mappings (backed by Postgres, `CRE.Linking.CacheEnabled`, enabled by default). | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -997,6 +997,8 @@ URL = "" # Default | |
| TLSEnabled = true # Default | ||
| # RequestTimeout bounds each organization lookup against the linking service. | ||
| RequestTimeout = '2s' # Default | ||
| # CacheEnabled turns on durable Postgres-backed caching of owner->orgID mappings. | ||
| CacheEnabled = true # Default | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: probably call it DurableCacheEnabled to underscore that the durable cache is enabled (the inmemory one is always on) |
||
|
|
||
| # Billing holds settings for connecting to the billing service. | ||
| [Billing] | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| package cre | ||
|
|
||
| import ( | ||
| "context" | ||
| "database/sql" | ||
| "errors" | ||
| "fmt" | ||
| "time" | ||
|
|
||
| "github.com/smartcontractkit/chainlink-common/pkg/services/orgresolver" | ||
| "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" | ||
| ) | ||
|
|
||
| // orgResolverCacheTable is the durable owner->orgID mapping table backing the | ||
| // OrgResolver cache. See migration 0307_org_resolver_cache.sql. | ||
| const orgResolverCacheTable = "cre.org_resolver_cache" | ||
|
|
||
| // orgResolverStore is a Postgres-backed implementation of orgresolver.Cache. | ||
| type orgResolverStore struct { | ||
| ds sqlutil.DataSource | ||
| } | ||
|
|
||
| // NewOrgResolverStore creates a durable cache store for the OrgResolver. | ||
| func NewOrgResolverStore(ds sqlutil.DataSource) *orgResolverStore { | ||
| return &orgResolverStore{ds: ds} | ||
| } | ||
|
|
||
| // Get returns the cached entry for owner. ok is false if no entry exists. | ||
| func (s *orgResolverStore) Get(ctx context.Context, owner string) (orgresolver.CacheEntry, bool, error) { | ||
| const q = `SELECT org_id, updated_at FROM ` + orgResolverCacheTable + ` WHERE workflow_owner = $1` | ||
| var row struct { | ||
| OrgID string `db:"org_id"` | ||
| UpdatedAt time.Time `db:"updated_at"` | ||
| } | ||
| if err := s.ds.GetContext(ctx, &row, q, owner); err != nil { | ||
| if errors.Is(err, sql.ErrNoRows) { | ||
| return orgresolver.CacheEntry{}, false, nil | ||
| } | ||
| return orgresolver.CacheEntry{}, false, fmt.Errorf("failed to get cached org for owner %s: %w", owner, err) | ||
| } | ||
| return orgresolver.CacheEntry{OrgID: row.OrgID, RefreshedAt: row.UpdatedAt}, true, nil | ||
| } | ||
|
|
||
| // Set stores or updates the mapping for owner. | ||
| func (s *orgResolverStore) Set(ctx context.Context, owner string, entry orgresolver.CacheEntry) error { | ||
| const q = ` | ||
| INSERT INTO ` + orgResolverCacheTable + ` (workflow_owner, org_id, updated_at) | ||
| VALUES ($1, $2, $3) | ||
| ON CONFLICT (workflow_owner) DO UPDATE SET org_id = EXCLUDED.org_id, updated_at = EXCLUDED.updated_at` | ||
| if _, err := s.ds.ExecContext(ctx, q, owner, entry.OrgID, entry.RefreshedAt); err != nil { | ||
| return fmt.Errorf("failed to upsert org for owner %s: %w", owner, err) | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| var _ orgresolver.Cache = (*orgResolverStore)(nil) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| -- +goose Up | ||
|
|
||
| CREATE TABLE IF NOT EXISTS cre.org_resolver_cache ( | ||
| workflow_owner TEXT NOT NULL PRIMARY KEY, | ||
| org_id TEXT NOT NULL, | ||
| updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() | ||
| ); | ||
|
|
||
| -- +goose Down | ||
|
|
||
| DROP TABLE IF EXISTS cre.org_resolver_cache; |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can you update PR description / link JIRA to clarify why durable caching is needed.