Ações são os métodos de um serviço que podem ser chamados externamente. As ações são chamadas via RPC (Remote Procedure Call). Elas são parecidas com requisições HTTP, com parâmetros de requisição e respostas de retorno.
Se você possuir várias instâncias de um serviço, o broker irá balancear as requisições entre as instâncias. Leia mais sobre balanceamento.
Chamada de serviços
Para chamar um serviço utilize o método broker.call
. O broker procura o serviço (e um nó) que possui a ação especificada e chama-a. A função retorna uma Promise
.
Sintaxe
const res = await broker.call(actionName, params, opts); |
O parâmetro actionName
é uma string separada por pontos. Sua primeira parte é o nome do serviço, enquanto a segunda parte representa o nome da ação. Então, se você tiver um serviço de posts
com uma ação create
, você pode chamá-la utilizando posts.create
.
O parâmetro params
é um objeto que é passado para a ação como parte do Contexto. O serviço pode acessá-lo através de ctx.params
. É opcional. Caso não seja definido, seu valor padrão é {}
.
O parâmetro opts
é um objeto utilizado para definir/substituir alguns parâmetros da solicitação, por exemplo: timeout
, retryCount
. É opcional.
Opções de chamada disponíveis:
Nome | Tipo | Valor padrão | Descrição |
---|---|---|---|
timeout |
Number |
null |
Tempo limite da requisição em milissegundos. Se a requisição atingir o tempo limite e você não definir fallbackResponse , o broker lançará um erro de RequestTimeout . Defina como 0 para desativar. Quando não definido, assumirá o requestTimeout definido nas configurações do broker. Leia mais. |
retries |
Number |
null |
Número de tentativas. Se a requisição atingir seu tempo limite, o broker irá tentar chamá-la novamente. Defina como 0 para desativar. Quando não definido, assumirá o retryPolicy.retries definido nas configurações do broker. Leia mais. |
fallbackResponse |
Any |
null |
Se a solicitação falhar, essa resposta alternativa será retornada. Leia mais. |
nodeID |
String |
null |
ID do nó de destino. Se definido, fará uma chamada direta para o nó especificado. |
meta |
Objeto |
{} |
Metadados da requisição. Acesse-o utilizando ctx.meta nas ações. Será transferido & mesclado em chamadas encadeadas. |
parentCtx |
Context |
null |
Instância de contexto pai Context . Use-o para encadear as chamadas. |
requestID |
String |
null |
ID de Requisição ou Correlação. Use-o para rastreamento. |
Utilização
Chamada sem parâmetros
const res = await broker.call("user.list"); |
Chamada com parâmetros
const res = await broker.call("user.get", { id: 3 }); |
Chamada com opções de chamada
const res = await broker.call("user.recommendation", { limit: 5 }, { |
Chamada com tratamento de erros
broker.call("posts.update", { id: 2, title: "Modified post title" }) |
Chamada direta: obtenha informações de saúde do nó “node-21”
const res = await broker.call("$node.health", null, { nodeID: "node-21" }) |
Metadados
Envie metadados para serviços com a propriedade meta
. Acesse-as utilizando ctx.meta
nas ações. Observe que em chamadas aninhadas o meta
é mesclado.
broker.createService({ |
meta
é enviada de volta ao serviço que fez a chamada do método. Você pode utilizar para enviar metadados extras de volta ao remetente da ação. Ex.: enviar cabeçalhos de resposta de volta para o API gateway ou gravar dados do usuário conectado nos metadados.
broker.createService({ |
Ao chamar ações dentro do serviço (this.actions.xy()
), você deve definir o campo parentCtx
de meta
para transmitir dados.
Chamadas internas
broker.createService({ |
Timeout
O tempo limite (timeout) também pode ser definido na definição de uma ação. Ele substitui a opção requestTimeout
do gerenciador de serviços (broker) global, mas não substitui o timeout
nas opções de chamada.
Exemplo
// moleculer.config.js
module.exports = {
nodeID: "node-1",
requestTimeout: 3000
};
// greeter.service.js
module.exports = {
name: "greeter",
actions: {
normal: {
handler(ctx) {
return "Normal";
}
},
slow: {
timeout: 5000, // 5 secs
handler(ctx) {
return "Slow";
}
}
},
Exemplos de chamada
// Utiliza o timeout global como 5000 |
Chamadas múltiplas
Chamar várias ações ao mesmo tempo também é possível. Para fazer isso, utilize broker.mcall
ou ctx.mcall
.mcall
com Objeto Array<Object\>
await broker.mcall( |
mcall
com Objeto e options.meta
await broker.mcall( |
opção settled
em broker.mcall
O método mcall
possui uma nova opção settled
para receber todas os resultados de Promises. Se settled: true
, mcall
retorna uma Promise resolvida para todos os casos e o response contém os status e as respostas de todas as chamadas. Note que, sem esta opção você não saberá quantas (nem quais) chamadas foram rejeitadas.
Exemplo
const res = await broker.mcall([ |
res
será algo parecido a
[ |
Streaming
O Moleculer suporta os streams do Node.js nos parâmetros da requisição params
e nas respostas. Utilize streams para transferir um arquivo recebido de um gateway, codificar/decodificar ou compactar/descompactar streams.
Exemplos
Enviar um arquivo como stream para um serviço
const stream = fs.createReadStream(fileName); |
Object Mode StreamingTambém há suporte para Object Mode Streaming. Para ativar, defina
$streamObjectMode: true
nometa
.
Note que params
deve ser um stream, você não pode adicionar nenhuma variável adicional a params
. Use a propriedade meta
para transferir dados adicionais.
Recebendo um stream em um serviço
module.exports = { |
Retornar um stream como resposta em um serviço
module.exports = { |
Processando o fluxo recebido no lado do remetente
const filename = "avatar-123.jpg"; |
Exemplo de serviço de codificação/decodificação AES
const crypto = require("crypto"); |
Visibilidade das ações
A ação tem uma propriedade visibility
para controlar sua visibilidade e a possibilidade de chamá-la por outros serviços.
Valores disponíveis:
published
ounull
: ação pública. Pode ser chamada localmente, remotamente, e pode ser publicada através da API Gatewaypublic
: ação pública, pode ser chamada localmente & remotamente, mas não publicada via API Gatewayprotected
: só pode ser chamado localmente (de serviços locais)private
: só pode ser chamado internamente (através dethis.actions.xy()
dentro do serviço)
Alterar visibilidade
module.exports = { |
O valor padrão é
null
(que será considerado comopublished
) devido à compatibilidade com versões anteriores.
Hooks de ação
Os hooks de ação são funções de middleware conectáveis e reutilizáveis que podem ser registradas em before
, after
ou em errors
nas ações de serviço. Um hook é uma função
ou uma String
. Em caso de String
, seu nome deve corresponder ao nome do método do serviço.
Before Hooks
Os before hooks são executados antes de uma ação ocorrer. Recebem ctx
e podem manipular ctx.params
, ctx.meta
, ou adicionar variáveis personalizadas em ctx.locals
para ser utilizadas nos handlers das ações. Se houver algum problema, o hook pode disparar um Error
. Por favor, observe que você não pode quebrar/ignorar as futuras execuções de hooks ou handlers da ação.
Principais usos:
- tratamentos de parâmetros
- validações de parâmetros
- pesquisar entidades
- autorização
After hooks
Os after hooks são executados após uma ação ocorrer. Recebem ctx
e response
. Eles podem manipular ou alterar completamente a resposta da ação. A resposta da ação deve sempre ser retornada no hook.
Principais usos:
- preencher propriedades
- remover dados confidenciais.
- envolver a resposta em um
Object
- converter a estrutura da resposta
Error hooks
Os hooks de erro são chamados quando um Erro
é lançado durante a chamada da ação. Recebe ctx
e err
. Pode lidar com o erro e retornar uma resposta (fallback) ou lançar o erro.
Principais usos:
- manipulação de erros
- encapsular o erro em outro
- resposta de fallback
Declaração de nível de serviço
Hooks podem ser atribuídos a uma ação específica (indicando o nome
) da ação, todas as ações (*
) no serviço ou indicando um coringa (e.x., create-*
). O último será aplicado a todas as ações cujo nome começa com create-
. Nomes de ação também podem ser combinados usando um símbolo pipe (por exemplo, create|update
)
Note que a ordem de registro do hook importa, pois define a sequência pela qual os hooks são executados. Para obter mais informações, dê uma olhada em ordem de execução dos hooks.
Before Hooks
const DbService = require("moleculer-db"); |
After & Error Hooks
const DbService = require("moleculer-db"); |
Declaração a nível de ação
Hooks também podem ser registrados dentro da declaração da ação.
Observe que a ordem de registro do hook importa, pois define a sequência pela qual os hooks são executados. Para obter mais informações, dê uma olhada em ordem de execução dos hooks.
Before & After hooks
broker.createService({ |
Ordem de execução
É importante ter em mente que os hooks têm uma ordem de execução específica. Isto é especialmente importante quando vários hooks estão registrados em diferentes níveis (serviço e/ou ação). Em geral, os hooks têm a seguinte lógica de execução:
before
hooks: global (*
)->
nível de serviço->
nível de ação.after
hooks: nível de ação->
nível de serviço->
global (*
).
Ao usar vários hooks pode ser difícil visualizar sua ordem de execução. No entanto você pode definir o
logLevel
paradebug
para rapidamente verificar a ordem de execução dos hooks de nível global e de serviço.
Exemplo de uma cadeia de execução de hook global, a nível de serviço & de ação
broker.createService({ |
Saída produzida por hooks globais, nível de serviço & de ação
INFO - Before all hook |
Reusabilidade
A maneira mais eficiente de reutilizar hooks é declarando-os como métodos de serviço em um arquivo separado e importando-os com o mecanismo mixin. Dessa forma, um único gancho pode ser facilmente compartilhado entre várias ações.
// authorize.mixin.js |
// posts.service.js |
Armazenamento local
A propriedade locals
do Contexto
é um armazenamento simples que pode ser usado para armazenar alguns dados adicionais e passá-los para o manipulador de ações. A propriedade locals
utilizada em conjunto com hooks formam um poderoso combo:
Configurando ctx.locals
em um before hook
module.exports = { |