Skip to content

Instantly share code, notes, and snippets.

@fjeldstad
Last active November 22, 2016 23:26
Show Gist options
  • Save fjeldstad/a233c25aae510af2265144605ceda4bc to your computer and use it in GitHub Desktop.
Save fjeldstad/a233c25aae510af2265144605ceda4bc to your computer and use it in GitHub Desktop.
const service, { sendCommand, query, publishEvent } = require('microservice');
const accountSuspensionService = service('account-suspension');
accountSuspensionService.onCommand('suspend-account', async function (command) {
const { id, reason } = command.payload;
const account = await query('get-account-by-id', { id });
if (account.status !== 'active') {
throw new Error(`Suspending an account requires status 'active', was instead '${account.status}'.`);
}
account.status = 'suspended';
account.suspendReason = reason;
await sendCommand('update-account', { account, expectedEtag: account._metadata.etag });
return publishEvent('account-suspended', { id, reason });
});
// Automatically suspend the account if it's Stripe subscription is cancelled.
accountSuspensionService.onEvent('stripe-subscription-cancelled', async function (event) {
await sendCommand('suspend-account', {
id: event.payload.metadata.accountId,
reason: 'Stripe subscription cancelled.'
});
});
// Also, let an admin suspend accounts manually.
// [below: somewhere in the admin GUI code]
// ...
$('#admin-suspend-account-button').on('click', (event) => {
sendCommand('suspend-account', { id: event.target.value, reason: 'Suspended by administrator.' });
});
// Silly example though; normally client code would not have access to `sendCommand` et al.
@fjeldstad
Copy link
Author

fjeldstad commented Nov 22, 2016

I exemplet ovan antas att det finns en annan service som hookat upp onCommand('update-account', ...) samt onQuery('get-account-by-id', ...), typ en account-crud-service. Kan förstås vara två separata lika gärna.

@fjeldstad
Copy link
Author

fjeldstad commented Nov 22, 2016

Terminologi:

command - en beskrivning av hur man vill ändra modellen/systemet. Kan misslyckas/ignoreras, t.ex. om kommandot är ogiltigt givet aktuellt state (som ovan). Har per definition sidoeffekter.

event - en beskrivning av något som faktiskt har hänt. Kan normalt inte misslyckas (utöver infrastrukturfel förstås).

query - en beskrivning av något man vill läsa ur systemet. Alltid sidoeffektfritt.

@fjeldstad
Copy link
Author

fjeldstad commented Nov 22, 2016

Endast en tjänst får hantera en viss kommandotyp eller querytyp. Om man skulle definiera flera tjänster som hanterar samma kommando/query bör systemet kasta ett fel under initfasen.

Däremot får obegränsat antal tjänster prenumerera på samma typ av event. Commands och queries är request/response, events är broadcast.

@fjeldstad
Copy link
Author

Infrastrukturmässigt skulle command- och query handlers kunna implementeras med ett enkelt HTTP-API medan event handlers skulle prenumerera på meddelanden från ett pub/sub-system.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment