Protocolo de armazenamento de estado para Agente MQTT

Importante

A Versão Prévia das Operações da Internet das Coisas do Azure – habilitadas pelo Azure Arc – está atualmente em versão prévia. Você não deve usar esse software em versão prévia em ambientes de produção.

Você precisará implantar uma nova instalação das Operações da Internet das Coisas do Azure quando uma versão em disponibilidade geral for disponibilizada. Você não poderá atualizar uma instalação de versão prévia.

Veja os Termos de Uso Complementares para Versões Prévias do Microsoft Azure para obter termos legais que se aplicam aos recursos do Azure que estão em versão beta, versão prévia ou que, de outra forma, ainda não foram lançados em disponibilidade geral.

O armazenamento de estado do MQ é um sistema de armazenamento distribuído dentro do cluster de Operações do Azure IoT. O armazenamento de estado oferece as mesmas garantias de alta disponibilidade que as mensagens MQTT no Agente MQTT. De acordo com as diretrizes de protocolo MQTT5/RPC, os clientes devem usar o MQTT5 para interagir com o armazenamento de estado do MQ. Este artigo fornece diretrizes de protocolo para desenvolvedores que precisam implementar seus próprios clientes de armazenamento de estado para Agente MQTT.

Visão geral do protocolo de armazenamento de estado

O armazenamento de estado do MQ dá suporte aos seguintes comandos:

  • SET<keyName><keyValue><setOptions>
  • GET<keyName>
  • DEL<keyName>
  • VDEL<keyName><keyValue> ## Exclui um determinado <keyName> se e somente se seu valor for <keyValue>

O protocolo usa o seguinte modelo de solicitação-resposta:

  • Solicitação. Os clientes publicam uma solicitação em um tópico do sistema de armazenamento de estado bem definido. Para publicar a solicitação, os clientes usam as propriedades e a carga necessárias descritas nas seções a seguir.
  • Resposta. O armazenamento de estado processa de maneira assíncrona a solicitação e responde no tópico de resposta que o cliente forneceu inicialmente.

O diagrama a seguir mostra a exibição básica da solicitação e da resposta:

Diagrama do processo básico de solicitação e resposta do repositório de estado.

Tópico do sistema de armazenamento de estado, QoS e propriedades MQTT5 necessárias

Para se comunicar com o armazenamento de estado, os clientes devem atender aos seguintes requisitos:

  • Use MQTT5. Para obter mais informações, consulte as especificações do MQTT 5.
  • Use QoS 1 (Qualidade de Serviço de nível 1). O QoS 1 está descrito na especificação MQTT 5.
  • Tenha um relógio que esteja dentro de um minuto do relógio do Agente MQTT.

Para se comunicar com o armazenamento de estado, os clientes devem PUBLISH solicitações para o tópico do sistema statestore/v1/FA9AE35F-2F64-47CD-9BFF-08E2B32A0FE8/command/invoke. Como o armazenamento de estado faz parte das Operações do Azure IoT, ele faz uma SUBSCRIBE implícita a este tópico sobre a inicialização.

Para criar uma solicitação, as seguintes propriedades MQTT5 são necessárias. Se essas propriedades não estiverem presentes ou a solicitação não for do tipo QoS 1, a solicitação falhará.

  • Tópico de Resposta. O armazenamento de estado responde à solicitação inicial usando esse valor. Como prática recomendada, formate o tópico de resposta como clients/{clientId}/services/statestore/_any_/command/invoke/response. Definir o tópico de resposta como statestore/v1/FA9AE35F-2F64-47CD-9BFF-08E2B32A0FE8/command/invoke ou como um que começa com clients/statestore/v1/FA9AE35F-2F64-47CD-9BFF-08E2B32A0FE8 não é permitido em uma solicitação de repositório de estado. O repositório de estado desconecta clientes MQTT que usam um tópico de resposta inválido.
  • Dados de Correlação. Quando o armazenamento de estado envia uma resposta, ele inclui os dados de correlação da solicitação inicial.

O diagrama a seguir mostra uma exibição expandida da solicitação e da resposta:

Diagrama do processo de solicitação e resposta expandido do repositório de estado.

Comandos com suporte:

Os comandos SET, GET e DEL se comportam conforme o esperado.

Os valores que o comando SET define e o comando GET recupera são dados binários arbitrários. O tamanho dos valores é limitado apenas pelo tamanho máximo do conteúdo MQTT e limitações de recursos do MQ e do cliente.

SET options

O comando SET fornece mais sinalizadores opcionais além dos básicos keyValue e keyName:

  • NX. Permite que a chave seja definida somente se ela ainda não existir.
  • NEX <value>. Permite que a chave seja definida somente se a chave não existir ou se o valor da chave já estiver definido como <valor>. O sinalizador NEX normalmente é usado para um cliente renovar a expiração (PX) em uma chave.
  • PX. Por quanto tempo a chave deve persistir antes de expirar, em milissegundos.

VDEL options

O comando VDEL é um caso especial do comando DEL. DEL exclui incondicionalmente o keyNamedeterminado. VDEL requer outro argumento chamado keyValue. VDEL só excluirá o keyName determinado se tiver o mesmo keyValue.

Formato de conteúdo

O formato de conteúdo PUBLISH do armazenamento de estado é inspirado em RESP3, que é o protocolo subjacente que o Redis usa. O RESP3 codifica o verbo, como SET ou GET, e os parâmetros, como keyName e keyValue.

Diferenciar maiúsculas de minúsculas

O cliente deve enviar os verbos e as opções em maiúsculas.

Formato de solicitação

As solicitações são formatadas como no exemplo a seguir. Após RESP3, o * representa o número de itens em uma matriz. O caractere $ é o número de caracteres na linha a seguir, excluindo o CRLF à direita.

Os comandos com suporte no formato RESP3 são GET, SET, DEL e VDEL.

*{NUMBER-OF-ARGUMENTS}<CR><LF>
${LENGTH-OF-NEXT-LINE}<CR><LF>
{COMMAND-NAME}<CR><LF>
${LENGTH-OF-NEXT-LINE}<CR><LF> // This is always the keyName with the current supported verbs.
{KEY-NAME}<CR><LF>
// Next lines included only if command has additional arguments
${LENGTH-OF-NEXT-LINE}<CR><LF> // This is always the keyValue for set
{KEY-VALUE}<CR><LF>

A saída de exemplo a seguir mostra o conteúdo RESP3 do armazenamento de estado:

*3<CR><LF>$3<CR><LF>set<CR><LF>$7<CR><LF>SETKEY2<CR><LF>$6<CR><LF>VALUE5<CR><LF>
*2<CR><LF>$3<CR><LF>get<CR><LF>$7<CR><LF>SETKEY2<CR><LF>
*2<CR><LF>$3<CR><LF>del<CR><LF>$7<CR><LF>SETKEY2<CR><LF>
*3<CR><LF>$4<CR><LF>vdel<CR><LF>$7<CR><LF>SETKEY2<CR><LF>$3<CR><LF>ABC<CR><LF>

Observação

Observe que SET requer propriedades MQTT5 adicionais, conforme explicado na seção Controle de versão e relógios lógicos híbridos.

Formato de resposta

Quando o armazenamento de estado detecta um conteúdo RESP3 inválido, ele ainda retorna uma resposta ao Response Topic do solicitante. Exemplos de conteúdo inválido incluem um comando inválido, um RESP3 ilegal ou um estouro inteiro. Um conteúdo inválido começa com a cadeia de caracteres -ERR e contém mais detalhes.

Observação

Uma solicitação GET, DEL ou VDEL em uma chave inexistente não é considerada um erro.

Se um cliente enviar um conteúdo inválido, o armazenamento de estado enviará uma carga semelhante ao seguinte exemplo:

-ERR syntax error

Resposta SET

Quando uma solicitação de SET for bem-sucedida, o armazenamento de estado retornará o seguinte conteúdo:

+OK<CR><LF>

Se uma solicitação SET falhar devido a uma verificação de condição especificada nas opções de conjunto NX ou NEX que significa que a chave não pode ser definida, o armazenamento de estado retornará a seguinte carga útil:

-1<CR><LF>

Resposta GET

Quando uma solicitação de GET é feita em uma chave inexistente, o armazenamento de estado retorna o seguinte conteúdo:

$-1<CR><LF>

Quando a chave é encontrada, o armazenamento de estado retorna o valor no seguinte formato:

${NumberOfBytes}<CR><LF>
{KEY-VALUE}

A saída do armazenamento de estado que retorna o valor 1234 se parece com o seguinte exemplo:

$4<CR><LF>1234<CR><LF>

Resposta DEL e VDEL

O armazenamento de estado retorna o número de valores excluídos em uma solicitação de exclusão. Atualmente, o armazenamento de estado só pode excluir um valor por vez.

:{NumberOfDeletes}<CR><LF> // Will be 1 on successful delete or 0 if the keyName is not present

A saída a seguir é um exemplo de um comando DEL bem-sucedido:

:1<CR><LF>

Se uma solicitação VDEL falhar porque o valor especificado não corresponde ao valor associado à chave, o armazenamento de estado retornará a seguinte carga útil:

-1<CR><LF>

-ERR respostas

A seguir está a lista atual de sequências de erros. Seu aplicativo cliente deve manipular cadeias de caracteres de erro desconhecido para dar suporte a atualizações no armazenamento de estado.

Cadeia de caracteres de erro retornada do armazenamento de estado Explicação
o registro de data e hora solicitado está muito distante no futuro; certifique-se de que os relógios do sistema do cliente e do corretor estejam sincronizados Carimbo de data/hora solicitado inesperado causado pelo armazenamento de estado e os relógios do cliente não estão sincronizados.
um token de esgrima é necessário para essa solicitação Ocorre um erro se uma chave estiver marcada com um token de cerca, mas o cliente não especificar o token de cerca.
o carimbo de data/hora do token de esgrima solicitado está muito distante no futuro; certifique-se de que os relógios do sistema do cliente e do corretor estejam sincronizados Carimbo de data/hora inesperado do token de cerca causado pela falta de sincronização dos relógios do cliente e do armazenamento de estado.
o token de cerca solicitado é uma versão inferior ao token de cerca que protege o recurso Versão incorreta do token de esgrima solicitado. Para obter mais informações, veja [Versionamento e relógios lógicos híbridos].(#versioning-and-hybrid-logical-clocks)
a cota foi excedida O armazenamento de estado tem uma cota de quantas chaves ele pode armazenar, que é baseada no perfil de memória do broker MQTT especificado.
erro de sintaxe A carga enviada não está de acordo com a definição do armazenamento de estado.
não autorizado Erro de autorização
comando desconhecido O comando não é reconhecido.
número errado de argumentos Número incorreto de argumentos esperados.
carimbo de data/hora ausente Quando os clientes fazem um SET, eles devem definir a propriedade de usuário MQTT5 __ts como um HLC representando seu registro de data e hora.
carimbo de data/hora malformado O registro de data e hora no __ts ou no token de esgrima não é legal.
o comprimento da chave é zero As chaves não podem ter comprimento zero no armazenamento de estado.

Controle de versão e relógios lógicos híbridos

Esta seção descreve como o armazenamento de estado lida com o controle de versão.

Versões como relógios lógicos híbridos

O armazenamento de estado mantém uma versão para cada valor armazenado. O armazenamento de estado poderia usar um contador de aumento de forma monotônica para manter versões. Em vez disso, o armazenamento de estado usa um HLC (Relógio Lógico Híbrido) para representar versões. Para obter mais informações, consulte os artigos sobre o design original de HLCs e a intenção por trás de HLCs.

O armazenamento de estado usa o seguinte formato para definir HLCs:

{wallClock}:{counter}:{node-Id}

O wallClock é o número de milissegundos desde a época do Unix. counter e node-Id funcionam como HLCs em geral.

Quando os clientes fazem um SET, eles devem definir a propriedade de usuário MQTT5 __ts como um HLC, representando seu carimbo de data/hora, com base no relógio atual do cliente. O armazenamento de estado retorna a versão do valor em sua mensagem de resposta. A resposta também é especificada como um HLC e também usa a propriedade de usuário MQTT5 __ts. O HLC retornado é sempre maior que o HLC da solicitação inicial.

Exemplo de configuração e recuperação da versão de um valor

Esta seção mostra um exemplo de configuração e obtenção da versão para um valor.

Um cliente define keyName=value. O relógio do cliente é 3 de outubro, 23:07:05 GMT. O valor do relógio é 1696374425000 milissegundos desde a época do Unix. Suponha que o relógio do sistema do armazenamento de estado seja idêntico ao relógio do sistema cliente. O cliente faz o comando SET conforme descrito anteriormente.

O diagrama a seguir ilustra o comando SET:

Diagrama do comando do repositório de estado para definir a versão de um valor.

A propriedade __ts (carimbo de data/hora) no conjunto inicial contém 1696374425000 como o relógio de parede do cliente, o contador como 0 e sua ID de nó como CLIENT. Na resposta, a propriedade __ts retornada pelo armazenamento de estado contém o wallClock, o contador incrementado por um e a ID do nó como StateStore. O repositório de estado poderia retornar um valor de wallClock mais alto se o relógio estivesse adiantado, com base na maneira como as atualizações do HLC funcionam.

Essa versão também é retornada em solicitações de GET, DEL e VDEL bem-sucedidas. Nessas solicitações, o cliente não especifica um __ts.

O diagrama a seguir ilustra o comando GET:

Diagrama do repositório de estado obtendo a versão de um valor.

Observação

O carimbo de data/hora __ts que o armazenamento de estado retorna é o mesmo que retornou na solicitação de SET inicial.

Se uma determinada chave for atualizada posteriormente com um novo SET, o processo será semelhante. O cliente deve definir sua solicitação __ts com base no relógio atual. O armazenamento de estado atualiza a versão do valor e retorna o __ts seguindo as regras de atualização do HLC.

Distorção de relógio

O armazenamento de estado rejeita um __ts (e também um __ft) que está mais de um minuto à frente do relógio local do armazenamento de estado.

O armazenamento de estado aceita um __ts que está atrás do relógio local do armazenamento de estado. Conforme especificado no algoritmo HLC, o armazenamento de estado define a versão da chave como seu relógio local porque ela é maior.

Tokens de bloqueio e isolamento

Esta seção descreve a finalidade e o uso de tokens de bloqueio e isolamento.

Tela de fundo

Suponha que haja dois ou mais clientes MQTT usando o armazenamento de estado. Ambos os clientes querem gravar em uma determinada chave. Os clientes do armazenamento de estado precisam de um mecanismo para bloquear a chave de forma que apenas um cliente por vez possa modificar uma determinada chave.

Um exemplo desse cenário ocorre em sistemas ativos e em espera. Pode haver dois clientes que executam a mesma operação e a operação pode incluir o mesmo conjunto de chaves do armazenamento de estado. Em um determinado momento, um dos clientes está ativo e o outro está pronto para assumir imediatamente se o sistema ativo trava ou falha. Idealmente, apenas um cliente deve gravar no armazenamento de estado em um determinado momento. No entanto, em sistemas distribuídos, é possível que ambos os clientes se comportem como se estivessem ativos e, simultaneamente, tentem gravar nas mesmas chaves. Esse cenário cria uma condição de corrida.

O armazenamento de estado fornece mecanismos para impedir essa condição de corrida usando tokens de isolamento. Para obter mais informações sobre tokens de isolamento e a classe de condições de corrida contra as quais eles foram projetados para se proteger, consulte este artigo.

Obter um token de isolamento

Este exemplo pressupõe que temos os seguintes elementos:

  • Client1 e Client2. Esses clientes são clientes de armazenamento de estado que atuam como um par ativo e em espera.
  • LockName. O nome de uma chave no armazenamento de estado que atua como o bloqueio.
  • ProtectedKey. A chave que precisa ser protegida contra vários gravadores.

Os clientes tentam obter um bloqueio como a primeira etapa. Eles recebem um bloqueio fazendo um SET LockName {CLIENT-NAME} NEX PX {TIMEOUT-IN-MILLISECONDS}. Lembre-se de Definir Opções que o sinalizador NEX significa que o SET só terá êxito se uma das seguintes condições for atendida:

  • A chave estava vazia
  • O valor da chave já está definido como <valor> e PX especifica o tempo limite em milissegundos.

Suponha que Client1 vá primeiro com uma solicitação de SET LockName Client1 NEX PX 10000. Essa solicitação lhe dá a propriedade de LockName para 10.000 milissegundos. Se Client2 tentar um SET LockName Client2 NEX ... enquanto Client1 tiver o bloqueio, o sinalizador NEX significará que a solicitação Client2 falhará. Client1 precisa renovar esse bloqueio enviando o mesmo comando SET usado para adquirir o bloqueio, se Client1 quiser continuar a propriedade.

Observação

Um SET NX é conceitualmente equivalente a AcquireLock().

Usar os tokens de isolamento em solicitações SET

Quando Client1 faz SET com êxito ("AquireLock") no LockName, o armazenamento de estado retorna a versão de LockName como um HLC (Relógio Lógico Híbrido) na propriedade __ts do usuário MQTT5.

Quando um cliente executa uma solicitação de SET, ele pode incluir opcionalmente a propriedade de usuário MQTT5 __ft para representar um "token de isolamento". O __ft é representado como um HLC. O token de isolamento associado a um determinado par chave-valor fornece verificação de propriedade de bloqueio. O token de isolamento pode vir de qualquer lugar. Para esse cenário, ele deve vir da versão do LockName.

O diagrama a seguir mostra o processo de Client1 fazer uma solicitação SET no LockName:

Diagrama de um cliente fazendo uma solicitação definida na propriedade de nome de bloqueio.

Em seguida, Client1 usa a propriedade __ts (Property=1696374425000:1:StateStore) não modificada como base da propriedade __ft na solicitação para modificar ProtectedKey. Como todas as solicitações SET, o cliente deve definir a propriedade __ts de ProtectedKey.

O diagrama a seguir mostra o processo de Client1 fazer uma solicitação SET no ProtectedKey:

Diagrama do cliente fazendo uma solicitação definida na propriedade de chave protegida.

Se a solicitação for bem-sucedida, desse ponto em ProtectedKey exigirá um token de isolamento igual ou maior que o especificado na solicitação SET.

Algoritmo de token de isolamento

O armazenamento de estado aceita qualquer HLC para o __ts de um par chave-valor, se o valor estiver dentro da distorção máxima do relógio. No entanto, o mesmo não ocorre em tokens de isolamento.

O algoritmo do armazenamento de estado para tokens de isolamento é o seguinte:

  • Se um par chave-valor não tiver um token de isolamento associado a ele e uma solicitação SET define __ft, o armazenamento de estado armazenará o __ft associado com o par chave-valor.
  • Se um par chave-valor tiver um token de isolamento associado a ele:
    • Se uma solicitação SET não tiver especificado __ft, rejeite a solicitação.
    • Se uma solicitação SET especificar um __ft que tenha um valor HLC mais antigo do que o token de isolamento associado ao par chave-valor, rejeite a solicitação.
    • Se uma solicitação SET especificar um __ft que tenha um valor HLC igual ou mais recente do que o token de isolamento associado ao par chave-valor, aceite a solicitação. O armazenamento de estado atualiza o token de isolamento do par chave-valor para ser o único definido na solicitação, se ele for mais recente.

Depois que uma chave é marcada com um token de isolamento, para que uma solicitação seja bem-sucedida, as solicitações DEL e VDEL também exigem que a propriedade __ft seja incluída. O algoritmo é idêntico ao anterior, exceto que o token de isolamento não é armazenado porque a chave está sendo excluída.

Comportamento do cliente

Esses mecanismos de bloqueio dependem de clientes serem bem comportados. No exemplo anterior, um Client2 mal comportado não podia ter o LockName e ainda executar com êxito um SET ProtectedKey escolhendo um token de isolamento mais recente que o token de ProtectedKey. O armazenamento de estado não está ciente de que LockName e ProtectedKey têm qualquer relação. Como resultado, o armazenamento de estado não executa a validação de que Client2 realmente possui o valor.

Os clientes que podem gravar chaves para as quais eles realmente não possuem o bloqueio são comportamentos indesejáveis. Você pode proteger contra esse mau comportamento do cliente implementando corretamente os clientes e usando a autenticação para limitar o acesso a chaves somente para clientes confiáveis.

Notificações

Os clientes podem se registrar no repositório de estado para receber notificações de chaves que estão sendo modificadas. Considere o cenário em que um termostato usa a chave do repositório de estado {thermostatName}\setPoint. Outros clientes do repositório de estado podem alterar o valor dessa chave para alterar o setPoint do termostato. Em vez de sondar alterações, o termostato pode se registrar no repositório de estado para receber mensagens quando {thermostatName}\setPoint é modificado.

Mensagens de solicitação KEYNOTIFY

Os clientes do repositório de estado solicitam que o repositório de estado monitore uma determinada keyName para alterações enviando uma mensagem de KEYNOTIFY. Assim como todas as solicitações do repositório de estado, os clientes PUBLISH uma mensagem QoS1 com essa mensagem por meio do MQTT5 para o tópico do sistema do repositório de estado statestore/v1/FA9AE35F-2F64-47CD-9BFF-08E2B32A0FE8/command/invoke.

O conteúdo da solicitação tem a forma a seguir:

KEYNOTIFY<CR><LF>
{keyName}<CR><LF>
{optionalFields}<CR><LF>

Onde:

  • KEYNOTIFY é um literal de cadeia de caracteres que especifica o comando.
  • {keyName} é o nome da chave para escutar as notificações. No momento, não há suporte para caracteres curinga.
  • {optionalFields} Os valores de campo opcionais com suporte no momento são:
    • {STOP} Se houver uma notificação existente com o mesmo keyName e clientId que essa solicitação, o repositório de estado a removerá.

A saída de exemplo a seguir mostra uma solicitação KEYNOTIFY para monitorar a chave SOMEKEY:

*2<CR><LF>
$9<CR><LF>
KEYNOTIFY<CR><LF>
$7<CR><LF>
SOMEKEY<CR><LF>

Mensagem de resposta KEYNOTIFY

Como todas as solicitações RPC do repositório de estado, o repositório de estado retorna sua resposta ao Response Topic e usa as propriedades de Correlation Data especificadas da solicitação inicial. Para KEYNOTIFY, uma resposta bem-sucedida indica que o repositório de estado processou a solicitação. Depois que o repositório de estado processa a solicitação com êxito, ela monitora a chave do cliente atual ou interrompe o monitoramento.

Com êxito, a resposta do repositório de estado é a mesma de um SET bem-sucedido.

+OK<CR><LF>

Se um cliente enviar uma solicitação KEYNOTIFY SOMEKEY STOP mas o repositório de estado não estiver monitorando essa chave, a resposta do repositório de estado será a mesma que tentar excluir uma chave que não existe.

:0<CR><LF>

Qualquer outra falha segue o padrão geral de relatório de erros do repositório de estado:

-ERR: <DESCRIPTION OF ERROR><CR><LF>

Tópicos de notificação KEYNOTIFY e ciclo de vida

Quando uma keyName sendo monitorada por meio de KEYNOTIFY é modificada ou excluída, o repositório de estado envia uma notificação ao cliente. O tópico é determinado por convenção – o cliente não especifica o tópico durante o processo de KEYNOTIFY.

O tópico é definido no exemplo a seguir. O clientId é uma representação codificada em hexadecimal de maiúsculas e minúsculas da ClientId MQTT do cliente que iniciou a solicitação KEYNOTIFY e keyName é uma representação codificada em hexadecimal da chave que foi alterada.

clients/statestore/v1/FA9AE35F-2F64-47CD-9BFF-08E2B32A0FE8/{clientId}/command/notify/{keyName}

Por exemplo, o MQ publica uma mensagem NOTIFY enviada para client-id1 com o nome da chave modificado SOMEKEY para o tópico:

clients/statestore/v1/FA9AE35F-2F64-47CD-9BFF-08E2B32A0FE8/636C69656E742D696431/command/notify/534F4D454B4559`

Um cliente que usa notificações deve SUBSCRIBE para este tópico e aguardar o SUBACK ser recebido antes de enviar solicitações KEYNOTIFY para que nenhuma mensagem seja perdida.

Se um cliente se desconectar, ele deverá assinar novamente o tópico de notificação KEYNOTIFY e reenviar o comando KEYNOTIFY para todas as chaves necessárias para continuar o monitoramento. Ao contrário das assinaturas MQTT, que podem ser mantidas em uma sessão não limpa, o repositório de estado remove internamente qualquer mensagens KEYNOTIFY quando um determinado cliente se desconecta.

Formato de mensagem de notificação KEYNOTIFY

Quando uma chave que está sendo monitorada por meio de KEYNOTIFY for modificada, o repositório de estado PUBLISH uma mensagem para o tópico de notificação seguindo o formato para os clientes do repositório de estado registrados para a alteração.

NOTIFY<CR><LF>
{operation}<CR><LF>
{optionalFields}<CR><LF>

Os seguintes detalhes estão incluídos na mensagem:

  • NOTIFY é um literal de cadeia de caracteres incluído como o primeiro argumento no conteúdo, indicando que uma notificação chegou.
  • {operation} é o evento que ocorreu. Atualmente, essas operações são:
    • SET o valor foi modificado. Essa operação só pode ocorrer como resultado de um comando SET de um cliente do repositório de estado.
    • DEL o valor foi excluído. Essa operação pode ocorrer devido a um comando DEL ou VDEL de um cliente do repositório de estado.
  • optionalFields
    • VALUE e {MODIFIED-VALUE}. VALUE é um literal de cadeia de caracteres que indica que o próximo campo, {MODIFIED-VALUE}, contém o valor para o qual a chave foi alterada. Esse valor é enviado somente em resposta a chaves que estão sendo modificadas devido a um SET.

A saída de exemplo a seguir mostra uma mensagem de notificação enviada quando a chave SOMEKEY é modificada para o valor abc, com o VALUE incluído porque a solicitação inicial especificou a opção GET:

*4<CR><LF>
$6<CR><LF>
NOTIFY<CR><LF>
$3<CR><LF>
SET<CR><LF>
$5<CR><LF>
VALUE<CR><LF>
$3<CR><LF>
abc<CR><LF>