Skip to content

Commit

Permalink
Use persistent actions
Browse files Browse the repository at this point in the history
  • Loading branch information
corrideat committed Jan 9, 2025
1 parent fdcc33d commit 4055758
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 19 deletions.
4 changes: 2 additions & 2 deletions backend/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -621,8 +621,8 @@ route.POST('/deleteContract/{hash}', {
// Authentication passed, now proceed to delete the contract and its associated
// keys
try {
await sbp('backend/deleteContract', hash)
return h.response()
const [id] = sbp('chelonia.persistentActions/enqueue', ['backend/deleteContract', hash])
return h.response({ id }).code(202)
} catch (e) {
switch (e.name) {
case 'BackendErrorNotFound':
Expand Down
11 changes: 9 additions & 2 deletions backend/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import sbp from '@sbp/sbp'
import chalk from 'chalk'
import { GIMessage } from '~/shared/domains/chelonia/GIMessage.js'
import '~/shared/domains/chelonia/chelonia.js'
import '~/shared/domains/chelonia/persistent-actions.js'
import { SERVER } from '~/shared/domains/chelonia/presets.js'
import type { SubMessage, UnsubMessage } from '~/shared/pubsub.js'
import { appendToIndexFactory, initDB, removeFromIndexFactory } from './database.js'
Expand Down Expand Up @@ -271,9 +272,9 @@ sbp('sbp/selectors/register', {
const resource = Buffer.from(await sbp('chelonia/db/get', resourceCid)).toString()
if (resource) {
if (resource.includes('previousHEAD') && resource.includes('contractID') && resource.includes('op') && resource.includes('height')) {
return sbp('backend/deleteContract', resourceCid)
return sbp('chelonia.persistentActions/enqueue', ['backend/deleteContract', resourceCid])
} else {
return sbp('backend/deleteFile', resourceCid)
return sbp('chelonia.persistentActions/enqueue', ['backend/deleteFile', resourceCid])
}
}
}))
Expand Down Expand Up @@ -428,6 +429,9 @@ sbp('okTurtles.data/set', PUBSUB_INSTANCE, createServer(hapi.listener, {
;(async function () {
await initDB()
await sbp('chelonia/configure', SERVER)
sbp('chelonia.persistentActions/configure', {
databaseKey: '_private_persistent_actions'
})
// Load the saved Chelonia state
// First, get the contract index
const savedStateIndex = await sbp('chelonia/db/get', '_private_cheloniaState_index')
Expand Down Expand Up @@ -469,6 +473,9 @@ sbp('okTurtles.data/set', PUBSUB_INSTANCE, createServer(hapi.listener, {
})
}))
}
sbp('chelonia.persistentActions/load').catch(e => {
console.error(e, 'Error loading persistent actions')
})
// https://hapi.dev/tutorials/plugins
await hapi.register([
{ plugin: require('./auth.js') },
Expand Down
2 changes: 1 addition & 1 deletion shared/domains/chelonia/chelonia.js
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ export default (sbp('sbp/selectors/register', {
})
}]
case NOTIFICATION_TYPE.DELETION:
return [k, (msg) => v(msg.data)]
return [k, (msg) => (v: Function)(msg.data)]
default:
return [k, v]
}
Expand Down
36 changes: 22 additions & 14 deletions shared/domains/chelonia/persistent-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,11 @@ class PersistentAction {
// 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)
this.timer = setTimeout(() => {
this.attempt().catch((e) => {
console.error('Error attempting persistent action', id, e)
})
}, this.options.retrySeconds * 1e3)
}
}

Expand Down Expand Up @@ -142,12 +146,11 @@ sbp('sbp/selectors/register', {

// Cancels a specific action by its ID.
// The action won't be retried again, but an async action cannot be aborted if its promise is stil attempting.
'chelonia.persistentActions/cancel' (id: UUIDV4): void {
async 'chelonia.persistentActions/cancel' (id: UUIDV4): Promise<void> {
if (id in this.actionsByID) {
this.actionsByID[id].cancel()
delete this.actionsByID[id]
// Likely no need to await this call.
sbp('chelonia.persistentActions/save')
return await sbp('chelonia.persistentActions/save')
}
},

Expand All @@ -172,19 +175,24 @@ sbp('sbp/selectors/register', {
this.actionsByID[action.id] = action
ids.push(action.id)
}
// Likely no need to await this call.
sbp('chelonia.persistentActions/save')
for (const id of ids) this.actionsByID[id].attempt()
sbp('chelonia.persistentActions/save').catch(e => {
console.error('Error saving persistent actions', e)
})
for (const id of ids) {
this.actionsByID[id].attempt().catch((e) => {
console.error('Error attempting persistent action', id, e)
})
}
return ids
},

// Forces retrying a given persisted action immediately, rather than waiting for the scheduled retry.
// - 'status.failedAttemptsSoFar' will still be increased upon failure.
// - Does nothing if a retry is already running.
// - Does nothing if the action has already been resolved, rejected or cancelled.
'chelonia.persistentActions/forceRetry' (id: UUIDV4): void {
'chelonia.persistentActions/forceRetry' (id: UUIDV4): void | Promise<void> {
if (id in this.actionsByID) {
this.actionsByID[id].attempt()
return this.actionsByID[id].attempt()
}
},

Expand All @@ -198,16 +206,16 @@ sbp('sbp/selectors/register', {
// TODO: find a cleaner alternative.
this.actionsByID[id].id = id
}
sbp('chelonia.persistentActions/retryAll')
return sbp('chelonia.persistentActions/retryAll')
},

// Retry all existing persisted actions.
// TODO: add some delay between actions so as not to spam the server,
// or have a way to issue them all at once in a single network call.
'chelonia.persistentActions/retryAll' (): void {
for (const id in this.actionsByID) {
sbp('chelonia.persistentActions/forceRetry', id)
}
'chelonia.persistentActions/retryAll' () {
return Promise.allSettled(
Object.keys(this.actionsByID).map(id => sbp('chelonia.persistentActions/forceRetry', id))
)
},

// Updates the database version of the attempting action list.
Expand Down

0 comments on commit 4055758

Please sign in to comment.