-
-
Notifications
You must be signed in to change notification settings - Fork 44
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
Support retriable Chelonia actions #1768
Support retriable Chelonia actions #1768
Conversation
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.
Preliminary review - looking really solid so far...!
'chelonia.persistentActions/_init' (): void { | ||
sbp('okTurtles.events/on', LOGIN, (function () { | ||
this.actionsByID = Object.create(null) | ||
this.databaseKey = `chelonia/persistentActions/${sbp('state/vuex/getters').ourIdentityContractId}` |
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.
Similarly, as this is a utility for Chelonia (and possibly in the future, an independent library), we cannot access 'state/vuex/getters'
either
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.
Ditto
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.
Looking really good @snowteamer!!
I'm wondering if we can also adjust the default options? Perhaps using the existing selector 'chelonia.persistentActions/configure'
?
frontend/main.js
Outdated
const databaseKey = `chelonia/persistentActions/${sbp('state/vuex/getters').ourIdentityContractId}` | ||
sbp('chelonia.persistentActions/configure', { databaseKey }) | ||
await sbp('chelonia.persistentActions/load') | ||
await sbp('chelonia.persistentActions/retryAll') |
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 'chelonia.persistentActions/load'
should automatically start the retries
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.
That would be fine, but on the other hand /save
doesn't stop the pending retries
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 shouldn't. The persistent action queue is something that is always active as long as it has actions inside of it while the app is running.
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 this is almost ready to merge.
@snowteamer - I think you might have missed this request from the previous review:
I'm wondering if we can also adjust the default options? Perhaps using the existing selector
'chelonia.persistentActions/configure'
?
This way we can override the default options for values like maxAttempts
and retrySeconds
.
Also added one more request about emitting events.
this.options.successInvocationSelector && | ||
await this.trySBP([this.options.successInvocationSelector, result]) |
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.
Can we refactor this to use events instead of options.successInvocationSelector
?
I think it makes sense to add at least two events using okTurtles.events
:
CHEL_PERSISTENT_ACTIONS_SUCCESS
- would be emitted above hereCHEL_PERSISTENT_ACTIONS_FAILURE
- would be emitted next to line 82 above, next to theerrorInvocation
, along with theerror
object
And if you think of any others that we should emit, feel free to suggest
d12f7aa
to
6192b3a
Compare
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.
Really impressive PR, @snowteamer. 👍👍👍
Just left a few comments.
status.lastError = error.message | ||
const anyAttemptLeft = options.maxAttempts > status.failedAttemptsSoFar | ||
if (!anyAttemptLeft) status.resolved = true | ||
status.nextRetry = anyAttemptLeft && !status.resolved |
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.
!status.resolved
could be ignored, I think.
status.nextRetry = anyAttemptLeft ? new Date(Date.now() + options.retrySeconds * 1e3).toISOString() : ''
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.
status.resolved
can be set independently by .cancel()
, therefore checking for anyAttemptLeft
was not enough
} | ||
}, | ||
|
||
'chelonia.persistentActions/enqueue' (...args): UUIDV4[] { |
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 it's preferable to declare possible types of args
as a comment above this function.
BTW: Why is it necessary to accept two types of arg
for PersistantAction
?
[invocation, options]
{ invocation, ...options }
I think the second format isn't necessary. And also invocation
could be added in options
of PersistantAction
instance.
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.
Good point about the args
comment.
Why is it necessary to accept two types of arg for PersistantAction?
Here I just followed the issue requirements.
And also invocation could be added in options of PersistantAction instance.
An invocation is required in any case, so I don't think invocation
should go in options
since it's not actually optional.
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.
Here I just followed the issue requirements.
Oh, it was a good thing @Silver-IT brought this up, because I missed this in my review.
This is not what the args look like according to the issue:
[invocation, options]
{ invocation, ...options }
Rather, they look like this:
[selector, arg1, arg2, arg3]
{ invocation, ...options }
So to answer @Silver-IT's question: the reason for allowing both types is because it makes the syntax when enqueing invocations simpler.
In most cases you can just pass in the sbpInvocation like so: [selector, arg1, arg2, arg3]
But when you want to adjust the defaults for a specific invocation, you use the second syntax.
I'm noticing that this code does not correctly handle the first syntax.
EDIT: oops, my mistake, the code seems to correctly handle this.
// TODO: find a cleaner alternative. | ||
this.actionsByID[id].id = id |
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 not to add id
in the arguments of PersistantAction
constructor?
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.
That's a possible choice, but I felt like it was not that great either
'chelonia.persistentActions/_init' (): void { | ||
this.actionsByID = Object.create(null) | ||
// Necessary for now as _init cannot be async. Becomes true when 'configure' has been called. | ||
this.ready = false |
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 can't find the place to set this.ready
true
in configure
function. Did you miss it by mistake?
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.
Indeed, good catch. BTW I've since replaced it by a direct check for availability of databaseKey
const anyAttemptLeft = options.maxAttempts > status.failedAttemptsSoFar | ||
if (!anyAttemptLeft) status.resolved = true | ||
status.nextRetry = anyAttemptLeft && !status.resolved | ||
? new Date(Date.now() + options.retrySeconds * 1e3).toISOString() |
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.
Using Date
is a bad idea for anything besides maybe logging. The reason is that the date could change arbitrarily. The better alternative is to use a monotonic timer for this, such as performance.now()
. I'm not sure exactly what this nextRetry
field is used for, exactly, though.
The second issue is the, like for the this.timer
assignment below, that 1e3
seems like a pretty low value for a retry
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.
The nextRetry
field is actually used for logging as per the issue requirement for 'chelonia.persistentActions/status'
1e3 seems like a pretty low value for a retry
options.retrySeconds
is a number of seconds, but we need milliseconds here, hence the 1e3
multiplier
// Schedule a retry if appropriate. | ||
if (status.nextRetry) { | ||
// Note: there should be no older active timeout to clear. | ||
this.timer = setTimeout(() => this.attempt(), this.options.retrySeconds * 1e3) |
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.
1e3 seems like a pretty low value
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.
Ditto
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.
Nice work @snowteamer. Looks almost ready to merge. Seems like the only thing remaining are the logging out related changes we discussed today.
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.
Great work @snowteamer! Approved & merged! 😄 🎉
Closes #1755
Summary of changes: