Add onSync callback for implementing action queues - #52
Conversation
…to finish in queue before destroy
| }) | ||
| let process = processAction.bind(this) | ||
| if (this.options.onActions) { | ||
| this.options.onActions(process, action, meta) |
There was a problem hiding this comment.
sendSynced will be sent just after onActions call. Don’t we need to do await or something?
There was a problem hiding this comment.
Also, we need to be ready for errors in onActions.
There was a problem hiding this comment.
onActions is not async so I didn't add an await
There was a problem hiding this comment.
То есть ты хочешь переделать протокол и отправлять synced не после inMap, inFilter и onAction (как сейчас) а сразу?
Почему такое изменение хочешь? Какие сайд-эффекты?
There was a problem hiding this comment.
Внутри inFilter происходит вызов коллбека access, и я подумал, что его лучше тоже вызывать в очереди, чтобы было так:
- выполняется action_1.access
- выполняется action_1.process
- выполняется action_2.access
- выполняется action_2.process
Про изменение протокола не подумал. Может, лучше сделать, что onActions будет вызываться вместо добавления action в лог? То есть сервер будет на onActions добавлять action в лог в порядке очереди, а inMap и inFilter будут вызываться как сейчас
| equal(pair.rightNode.log.actions(), [{ type: 'a1' }]) | ||
| }) | ||
|
|
||
| test('calls onActions if present', async () => { |
There was a problem hiding this comment.
I don’t see how onActions works in a test. I am not sure that we are property testing it.
| inMap?: LogMapper | ||
|
|
||
| /** | ||
| * Function that will be called before node sends 'synced' |
There was a problem hiding this comment.
It is unclear how to use it and why. We need to say a little more details here.
|
Can you explain me this API? I didn’t get what it I tried to look at Logux Server code, but it didn’t help any Logux Core changes should be self-explained. You can switch to Russian if it will be simpler. |
Спасибо за ревью. На данный момент, для каждого API, которое я добавил, позволяет вызывать inMap, inFilter и добавление action в лог тогда, когда будет нужно. В нашем случае, это будет происходить в очереди. То есть:
ignoreDestroying нужен для того, чтобы завершить выполнение всех action в очереди перед выключением сервера. Используется здесь: https://github.com/logux/server/pull/146/files#diff-dcb9d56556bf3885bd0d0fd9d88b318f0bdeddd59f85fe50c319ae959bfebd85R230. Без него может получится так:
|
Всё равно не понимаю API. Дай примеры на псевдо-коде как её использовать (абстрактно, вне сервера).
А мы можем избежать вставки |
Примеры использования: onActions(process, action, meta) {
myActionQueue.schedule(async () => {
await process(action, meta)
})
}```ts
onActions(process, action, meta) {
myActions.push({process, action, meta})
if (myActions.length === 10) {
myActions.forEach(async ({process, action, meta}) => {
await process(action, meta)
})
myActions.clear()
}
} |
|
И как эти примеры будут работать? Объясни когда вызовутся |
|
И объясни почему в API там |
|
Добавил комментарии: onActions(process, action, meta) {
// Вызываем process(action, meta) не сразу, а сохраняем в очередь
// myActionQueue будет вызывать коллбеки по очереди, а не параллельно
myActionQueue.schedule(async () => {
await process(action, meta) // Вызовет inMap, inFilter и добавить action в лог
})
}onActions(process, action, meta) {
// Вызываем process(action, meta) не сразу, а когда накопиться 10 action'ов
myActions.push({process, action, meta})
if (myActions.length === 10) {
myActions.forEach(async ({process, action, meta}) => {
await process(action, meta) // Вызовет inMap, inFilter и добавить action в лог
})
myActions.clear()
}
}В API там process, потому что внутри него вызываются InMap, inFilter и происходит добавление action в лог. Получается что нужно вызвать process(action, meta) и он вызовет inMap и inFilter. |
|
А почему нельзя вернуть Промис и вызвать |
|
И в чём тогда разница с |
|
Поменял, чтобы inMap и inFilter вызывались, как сейчас, а onActions будет вызываться вместо добавления action в log (сервер сам будет добавлять action в лог, но уже в очереди, а не сразу). onActions(action, meta) {
// Add action to the log later
myActionQueue.schedule(() => {
actionLog.add(action, meta)
})
} |
| /** | ||
| * Function that will be called instead of adding action to the log | ||
| * after inMap and inFilter have been called. | ||
| * Use it if you want more control over when an action will be added to the log |
There was a problem hiding this comment.
| * Use it if you want more control over when an action will be added to the log | |
| * | |
| * Use it if you want more control over when an action will be added to the log. |
| * Function that will be called instead of adding action to the log | ||
| * after inMap and inFilter have been called. | ||
| * Use it if you want more control over when an action will be added to the log | ||
| * @example |
There was a problem hiding this comment.
The project uses different syntax for examples in TypeDoc
| * } | ||
| * ``` | ||
| */ | ||
| onActions?: ActionsCallback |
There was a problem hiding this comment.
There are two problems with naming:
onActionshasson the end, but we call it for single action.log.add()also add “action”, why we are not callingonActionthere?
What do you think about onSync?
| equal(catched, [error]) | ||
| }) | ||
|
|
||
| test('actions are added to the log if onActions is present and if actions were added to the log inside it', async () => { |
There was a problem hiding this comment.
Too long line. Let’s name shorter to avoid lines > 80 symbols.
| test('actions are added to the log if onActions is present and if actions were added to the log inside it', async () => { | ||
| let pair = await createTest(created => { | ||
| created.rightNode.options.inFilter = async (action, meta) => { | ||
| type(meta.id, 'string') |
There was a problem hiding this comment.
You can remove this checks since we are not testing inFiler and inMap
| return [{ type: action.type + '1' }, meta] | ||
| } | ||
| created.rightNode.options.onActions = (action, meta) => { | ||
| created.rightNode.log.add(action, meta) |
There was a problem hiding this comment.
This test will not find that onActions is not calling (because log.add is default behavior)
There was a problem hiding this comment.
For instance, let’s put actions to an array and then check the array that it contains actions and log is empty.
| equal(pair.rightNode.log.actions(), [{ type: 'a1' }, { type: 'b1' }]) | ||
| }) | ||
|
|
||
| test('actions are not added to the log if onActions is present and if actions were not added to the log inside it', async () => { |
There was a problem hiding this comment.
We don’t need this test if we will check array filling in test above
Co-authored-by: Andrey Sitnik <andrey@sitnik.ru>
Co-authored-by: Andrey Sitnik <andrey@sitnik.ru>
| test('onSync is called instead of adding an action to the log', async () => { | ||
| let actions = [] | ||
| let pair = await createTest(created => { | ||
| created.rightNode.options.onSync = (action, meta) => { |
There was a problem hiding this comment.
I mean let’s remove type(action, 'object') from inMap/inFilter.
The inMap/inFilter were useful to test that we call onSync after them.
|
I've changed an API in order to support calling onSync(processAction, action, meta) {
// Process an action later
myActionQueue.schedule(async () => {
await processAction(action, meta) // will call `inMap`, `inFilter` and `Log#add`
})
} |
| * } | ||
| * ``` | ||
| */ | ||
| onSync?: SyncCallback |
There was a problem hiding this comment.
I have plan later to replace inFiler/inMap with onSync (are you agree that it is possibe?)
Can you rename onSync to onReceive (so later we will be able to add onSend for outFilter/outMap)?
There was a problem hiding this comment.
Yes this should be possible
* add onActions callback for implementing action queues * add ignoreDestroying to meta in order to support waiting for actions to finish in queue before destroy * add test for ignoreDestroying, export ActionsCallback type * handle error in onActions * improve onActions description * add 1 more test for onActions * remove ignoreDestroying, move related logic to logux server * use different code example for onActions * fix typo * call inMap and inFilter outside of onActions * review docs issue * Update base-node/index.d.ts Co-authored-by: Andrey Sitnik <andrey@sitnik.ru> * Update base-node/index.d.ts Co-authored-by: Andrey Sitnik <andrey@sitnik.ru> * rename onActions to onSync, improve onSync tests * add inMap and inFilter to the onSync test * change onSync api to support calling access inside of queue * rename onSync to onReceive --------- Co-authored-by: Andrey Sitnik <andrey@sitnik.ru>
Related to logux/logux#54
This PR adds "onSync" callback that can be used in @logux/server to implement action queues.