-
Notifications
You must be signed in to change notification settings - Fork 51
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
Removal of caching for services #394
Conversation
…o-paging methods.
if snInfo == nil { | ||
return fmt.Errorf("Service network %s for account %s not found", gw.Name, config.AccountID) | ||
} |
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.
With the change on FindX
logic to raise a "not found" error, these additional nil checks on the return value are no longer required.
type NotFoundError struct { | ||
ResourceType string | ||
Name string | ||
} |
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.
Getting something that looked and behaved sensibly for error handling and identifying errors of this type took me a while. For folks more familiar with Go please feel free to suggest an alternate approach if you think there's a better option.
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.
std lib style https://pkg.go.dev/errors
// Error and constructor
var ErrNotFound = errors.New("resource not found")
func NewNotFound(name, restype string) {
return fmt.Errorf("name: %s, type: %s, err: %w", name, restype, ErrNotFound)
}
// In lattice interface
func FindResource(res Req) (Resp, error) {
return nil, NewNotFound(res.Name, res.Type)
}
// Handle error
resp, err := lattice.FindResource(ctx, req)
if err != nil {
if errors.Is(err, ErrNotFound) {
// handle error
} else {
...
}
}
err := d.ListServiceNetworksPagesWithContext(ctx, input, func(page *vpclattice.ListServiceNetworksOutput, lastPage bool) bool { | ||
for _, sn := range page.Items { | ||
result = append(result, sn) | ||
} | ||
input.NextToken = resp.NextToken | ||
resp, err = d.ListServiceNetworksWithContext(ctx, input) | ||
return true | ||
}) |
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.
I've updated all the methods here to use automatic pagination as per @mikhail-aws suggestion in previous PR. The way these methods work is you provide a function for them to call for each page found and you return true
if you want the call to keep fetching pages.
This makes mocking a little more complicated but it's not too hard to follow.
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.
compact version:
7 func (d *defaultLattice) ListServiceNetworksAsList(ctx context.Context, input *vpclattice.ListServiceNetworksInput) ([]*vpclattice.ServiceNetworkSummary, error) {
8 result := []*vpclattice.ServiceNetworkSummary{}
9 err := d.ListServiceNetworksPagesWithContext(ctx, input, func(page *vpclattice.ListServiceNetworksOutput, lastPage bool) bool {
10 result = append(result, page.Items...)
return true
11 })
12 return result, err
13 }
Generic get all pages function. Since every page is a struct, getting Items from page can be done through reflection, or explicitly written as getPageItems, that return items from page.
func ListAll[REQ any, ITEM any, PAGE any](
ctx context.Context, req REQ,
listPages func(context.Context, REQ, func(PAGE, bool) bool, ...request.Option) error,
getPageItems func(PAGE) []ITEM)([]ITEM, error) {
out := []ITEM{}
err := listPages(ctx, req, func(page PAGE, _ bool) bool {
out = append(out, getPageItems(page)...)
return true
})
return out, err
}
func (l *Lattice) ListServiceNetworksAsList(ctx context.Context, in *vpclattice.ListServiceNetworksInput) ([]*vpclattice.ServiceNetworkSummary, error) {
return ListAll(
ctx, in, l.c.ListServiceNetworksPagesWithContext,
func(page *vpclattice.ListServiceNetworksOutput) []*vpclattice.ServiceNetworkSummary {
return page.Items
})
}
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.
I dont see any value in unit-tests with mocks for these Lattice wrapper functions. As you mentioned, it's painful and kind of self-fulfilling prophecy.
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.
I am curious what the benefit of ListServiceNetworksPagesWithContext(ctx, input, fn)
compared to the old NextToken
way? (Still learning this part)
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.
Honestly I'm not convinced it's that big a win. The logic is a little harder to wrap your head around, but it means we can't get into an infinite loop or accidently omit pages by mishandling NextToken
.
// if we still want this method, we should tag the things we create with the test suite | ||
func (env *Framework) CleanTestEnvironment(ctx context.Context) { |
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.
IMO the "best" way to clean up the test environment is via the new e2e-clean target. Tracking these resources as side-effects of various creation calls seems unreliable, similar to the reasons we're eliminating the LatticeDataStore
cache.
Given we're not using the cleanup methods today, I think removing them is better for now than continuing to maintain this unused code.
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.
Interesting idea, do you want to remove cleanup after each test and do only one at the very end of all tests?
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.
Removing resources as each test finishes is what it does today. We don't call anything at the end of all tests. These Clean*
methods are currently unused.
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.
Didnt have a chance review everything. Left minor comments.
type NotFoundError struct { | ||
ResourceType string | ||
Name string | ||
} |
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.
std lib style https://pkg.go.dev/errors
// Error and constructor
var ErrNotFound = errors.New("resource not found")
func NewNotFound(name, restype string) {
return fmt.Errorf("name: %s, type: %s, err: %w", name, restype, ErrNotFound)
}
// In lattice interface
func FindResource(res Req) (Resp, error) {
return nil, NewNotFound(res.Name, res.Type)
}
// Handle error
resp, err := lattice.FindResource(ctx, req)
if err != nil {
if errors.Is(err, ErrNotFound) {
// handle error
} else {
...
}
}
err := d.ListServiceNetworksPagesWithContext(ctx, input, func(page *vpclattice.ListServiceNetworksOutput, lastPage bool) bool { | ||
for _, sn := range page.Items { | ||
result = append(result, sn) | ||
} | ||
input.NextToken = resp.NextToken | ||
resp, err = d.ListServiceNetworksWithContext(ctx, input) | ||
return true | ||
}) |
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.
compact version:
7 func (d *defaultLattice) ListServiceNetworksAsList(ctx context.Context, input *vpclattice.ListServiceNetworksInput) ([]*vpclattice.ServiceNetworkSummary, error) {
8 result := []*vpclattice.ServiceNetworkSummary{}
9 err := d.ListServiceNetworksPagesWithContext(ctx, input, func(page *vpclattice.ListServiceNetworksOutput, lastPage bool) bool {
10 result = append(result, page.Items...)
return true
11 })
12 return result, err
13 }
Generic get all pages function. Since every page is a struct, getting Items from page can be done through reflection, or explicitly written as getPageItems, that return items from page.
func ListAll[REQ any, ITEM any, PAGE any](
ctx context.Context, req REQ,
listPages func(context.Context, REQ, func(PAGE, bool) bool, ...request.Option) error,
getPageItems func(PAGE) []ITEM)([]ITEM, error) {
out := []ITEM{}
err := listPages(ctx, req, func(page PAGE, _ bool) bool {
out = append(out, getPageItems(page)...)
return true
})
return out, err
}
func (l *Lattice) ListServiceNetworksAsList(ctx context.Context, in *vpclattice.ListServiceNetworksInput) ([]*vpclattice.ServiceNetworkSummary, error) {
return ListAll(
ctx, in, l.c.ListServiceNetworksPagesWithContext,
func(page *vpclattice.ListServiceNetworksOutput) []*vpclattice.ServiceNetworkSummary {
return page.Items
})
}
err := d.ListServiceNetworksPagesWithContext(ctx, input, func(page *vpclattice.ListServiceNetworksOutput, lastPage bool) bool { | ||
for _, sn := range page.Items { | ||
result = append(result, sn) | ||
} | ||
input.NextToken = resp.NextToken | ||
resp, err = d.ListServiceNetworksWithContext(ctx, input) | ||
return true | ||
}) |
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.
I dont see any value in unit-tests with mocks for these Lattice wrapper functions. As you mentioned, it's painful and kind of self-fulfilling prophecy.
err := d.ListServiceNetworksPagesWithContext(ctx, input, func(page *vpclattice.ListServiceNetworksOutput, lastPage bool) bool { | ||
for _, sn := range page.Items { | ||
result = append(result, sn) | ||
} | ||
input.NextToken = resp.NextToken | ||
resp, err = d.ListServiceNetworksWithContext(ctx, input) | ||
return true | ||
}) |
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.
I am curious what the benefit of ListServiceNetworksPagesWithContext(ctx, input, fn)
compared to the old NextToken
way? (Still learning this part)
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.
Overall, LGTM, both current IsNotFoundError()
and the error handling way the @mikhail-aws mentions are ok for me
|
||
func (e *NotFoundError) Error() string { | ||
return fmt.Sprintf("%s %s not found", e.ResourceType, e.Name) | ||
} |
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.
Do we need to change to:
return fmt.Sprintf("Lattice %s %s not found", e.ResourceType, e.Name)
So that log can show "Lattice service xxxxxx not found" and "Lattice service network xxxxxx not found"
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.
I'll update this for next PR
|
||
var svcMatch *vpclattice.ServiceSummary | ||
err := d.ListServicesPagesWithContext(ctx, &input, func(page *vpclattice.ListServicesOutput, lastPage bool) bool { | ||
for _, svc := range page.Items { |
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.
Does FindService() also need to check:
acctIdMatches, err1 := accountIdMatches(optionalAccountId, *r.Arn)
if !acctIdMatches {
continue
}
in case in the future we support RAM share lattice Service in the controller and one current account Service and one foreign Service have the same name. (check accountId at least not harmful?)
What type of PR is this?
cleanup
Which issue does this PR fix:
n/a
What does this PR do / Why do we need it:
This is the second refactor to ultimately eliminate the
LatticeDataStore
. This PR eliminates caching for services. Prev PR: #391This PR eliminates use of the data store for service operations and instead calls the VPC Lattice API directly. This increases call volume to the
ListServices
API, but centralizes this logic in a way that should be more reliably cacheable in future.Additional changes include minor refactoring for readability, typos, or consistency in naming. Also, I had some follow up actions from the previous PR addressed here. These include:
List*PagesWithContext
)Testing done on this change:
Automated tests (unit/integration).
make test
e2e tests
Will this PR introduce any new dependencies?:
No
Will this break upgrades or downgrades. Has updating a running cluster been tested?:
n/a
Does this PR introduce any user-facing change?:
No
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.