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
docstore: distinguish ordered from unordered action lists #1742
Conversation
- Clarify the meaning of running an ActionList in order. - Add the ActionList.Unordered method, so users can request out-of-order execution. This also affects errors: in Unordered mode, all actions are run regardless of errors. - To accommodate unordered-mode errors, change ActionList.Do to return a special error type that can represent multiple errors along with the corresponding actions' positions. Implementing Unordered is left for a subsequent PR. Updates google#1660.
Codecov Report
@@ Coverage Diff @@
## master #1742 +/- ##
=========================================
- Coverage 73.89% 73.69% -0.2%
=========================================
Files 75 75
Lines 7764 7801 +37
=========================================
+ Hits 5737 5749 +12
- Misses 1623 1642 +19
- Partials 404 410 +6
Continue to review full report at Codecov.
|
|
||
// An ActionListError contains all the errors encountered from a call to RunActions, | ||
// and the positions of the corresponding actions. | ||
type ActionListError []struct { |
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.
Maybe ActionListErrors
or ActionErrorList
?
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 think singular (ActionListError) makes a little more sense. It is one error
, even though it holds multiple things. For comparison, Hashicorp's version of this is called multierror.
PTAL. |
internal/docstore/docstore.go
Outdated
// Do executes the action list. | ||
// In ordered mode (when the Unordered method was not called on the list), execution | ||
// will stop after the first action that fails. | ||
// In unordered mode, all the actions will be executed. In either mode, as a special |
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.
Consider moving this "none of the actions" thing to be first? E.g.,
// Do executes the action list.
//
// If any of the actions are invalid (for example, ...), it returns an error, and no actions are executed.
//
// If ordered mode...
//
// In unordered mode...
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 still think this (the "special case") should be moved up above, or at least not be part of the "unordered mode" paragraph (since it applies to both modes).
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.
Done.
internal/docstore/docstore.go
Outdated
// An ActionListError is returned by ActionList.Do. It contains all the errors | ||
// encountered while executing the ActionList, and the positions of the corresponding | ||
// actions. | ||
type ActionListError = driver.ActionListError |
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 think you should copy the type here; otherwise, the end user has to look at the driver package to see what an ActionListError
consists of.
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.
Done.
internal/docstore/driver/driver.go
Outdated
return strings.Join(s, "; ") | ||
} | ||
|
||
func (e ActionListError) Unwrap() error { |
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 don't understand what "Unwrap" is for. I find it surprising that it returns nil
if there's more than one error. What is this used for?
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.
OK, now I see it used above. Maybe "SingleError" or something? At least a docstring.
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.
This is for conformance with the new errors stuff. See https://tip.golang.org/pkg/errors/#Wrapper.
internal/docstore/docstore.go
Outdated
return alerr | ||
} | ||
alerr = l.coll.driver.RunActions(ctx, das, l.unordered) | ||
if alerr != nil { // Explicit non-nil check is necessary because alerr is not of type error. |
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.
Why is the nil check needed? Isn't it always safe to range
over the slice?
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.
It is safe to range over a nil slice. But I need the explicit nil check somewhere. If there is no error, I want to return the interface value (nil, nil)
from this function, not (nil, ActionListError)
. See https://golang.org/doc/faq#nil_error.
My comment on this line was supposed to explain this. Let me know how I can improve it.
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.
Oh I see. I was misled by the comment being right before the range
.
Maybe:
alerr = ...
if len(alerr) == 0 {
return nil // Explicitly return nil, because alerr is not of type error
}
for i := range ...{}
return alerr
```
I don't feel that strongly about this, but I didn't get the comment on first read.
PTAL. |
internal/docstore/docstore.go
Outdated
// Do executes the action list. | ||
// In ordered mode (when the Unordered method was not called on the list), execution | ||
// will stop after the first action that fails. | ||
// In unordered mode, all the actions will be executed. In either mode, as a special |
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 still think this (the "special case") should be moved up above, or at least not be part of the "unordered mode" paragraph (since it applies to both modes).
// In unordered mode, all the actions will be executed. In either mode, as a special | ||
// case, none of the actions will be executed if any is invalid (for example, a Put | ||
// whose document is missing its key field). | ||
func (l *ActionList) Do(ctx context.Context) error { |
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.
If this function always returns ActionListError
, maybe state that more explicitly?
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.
Clarified.
internal/docstore/docstore.go
Outdated
return alerr | ||
} | ||
alerr = l.coll.driver.RunActions(ctx, das, l.unordered) | ||
if alerr != nil { // Explicit non-nil check is necessary because alerr is not of type error. |
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.
Oh I see. I was misled by the comment being right before the range
.
Maybe:
alerr = ...
if len(alerr) == 0 {
return nil // Explicitly return nil, because alerr is not of type error
}
for i := range ...{}
return alerr
```
I don't feel that strongly about this, but I didn't get the comment on first read.
…tore-actionlist-ordering
Clarify the meaning of running an ActionList in order.
Add the ActionList.Unordered method, so users can request out-of-order execution.
This also affects errors: in Unordered mode, all actions are run regardless of errors.
To accommodate unordered-mode errors, change ActionList.Do to return a special error
type that can represent multiple errors along with the corresponding actions' positions.
Implementing Unordered is left for a subsequent PR.
Updates #1660.