Histórico da Página
Índice | ||
---|---|---|
|
01. Apresentação
Este documento técnico tem por objetivo auxiliar os desenvolvedores dos segmentos na criação de classes que "publicam" e/ou "consomem" mensagens através da plataforma Totvs SmartLink.
02. Responsabilidades
O desenvolvimento e manutenção dos publicadores e consumidores de mensagens são de responsabilidade das equipes de segmentos. Os artefatos genéricos que controlam a fila de execução das mensagens são de responsabilidade da equipe de Framework.
03. Implementando um publicador de mensagens
Para que uma classe seja um publicador de mensagens, deve-se atender aos pré-requisitos listados abaixo:
Pré-requisitos
- Criar um projeto (classLibrary .NET) na solution do segmento em questão, com o seguinte padrão de nome: RM.[Segmento].XXX.SmartLink.Service.
- Exemplo: RM.Glb.SGDP.SmartLink.Service.dll
- Adicionar referência para a dll "RM.Lib.SmartLink.dll";
Criar uma classe que receba em seu construtor instâncias das seguintes interfaces:
"IRMSSmartLinkPublisherService": interface de serviço responsável em incluir a mensagem na fila do RM.SmartLink.Client.
Foi criada na Lib uma classe de "Factory" responsável em fornecer uma instância para interface "IRMSSmartLinkPublisherService". Trata-se da classe "RMSSmartLinkPublisherFactory"Informações .
Basta chamar seu método público "NewSmartLinkPublisher" para obter uma instância contendo essa responsabilidade."IRMSLogger": serviço usado para incluir logs relacionados à regra de negócio em questão.
Informações Todos os logs adicionados nesse serviço serão gravados automaticamente na tabela "GTotvsLinkLog"
Para publicar uma mensagem na fila do RM.SmartLink.Client, basta chamar o método "AddMessage" da instância de interface "IRMSSmartLinkPublisherService". Os seguinte dados devem ser enviados através de uma classe de parâmetros do tipo "SmartLinkPublisherAddMessageParams":
Propriedade Descrição Command Nome do comando a ser incluído na fila do SmartLink. Ex: SGDPUpdateTenantMetada CorrelatedId Pode ser ser enviado nessa propriedade um identificador (guid) que correlacionam mensagens de envio e resposta. Data Dados da mensagem contendo informações relacionadas ao negócio. Pode ser em qualquer formato (json, xml, etc) desde que o consumidor consiga interpretá-lo.
RouterMessage Rota de envio da mensagem. Será concatenada ao endpoint do serviço do Totvs SmartLink.Server. ex: /api/v1/link/send/SGDPMaskResponse/SGDP
- Diagrama de classes contendo um publicador de mensagem de exemplo:
...
Bloco de código | ||||||
---|---|---|---|---|---|---|
| ||||||
using Newtonsoft.Json.Linq; using RM.Glb.SGDP.SmartLink.Service.Domain.Interfaces; using RM.Lib.DataGlb.SGDP.SmartLink.Service.Domain.Interfaces; using RM.Lib.Log; using RM.Lib.SmartLink.Domain.DataModel; using RM.Lib.SmartLink.Domain.Interfaces; using RM.Lib.SmartLink.Domain.Publisher; using System; using System.Collections.Generic; using System.Linq; namespace RM.Glb.SGDP.SmartLink.Service { public class GlbSGDPPublisherMessageService : IGlbSGDPPublisherMessageService { private readonly IGlbSGDPResolverService _SGDPResolverServicesgdpResolverService; private readonly IRMSSmartLinkPublisherService _SmartLinkPublisherServicesmartLinkPublisherService; private readonly IRMSLogger _LogServicelogService; private const string ctSGDPMaskResponseEndPointctSGDPUpdateTenantMetadataEndPoint = "/api/v1/link/send/SGDPMaskResponseSGDPUpdateTenantMetadata/SGDP"; private const string ctSGDPDataResponseEndPoint = "/api/v1/link/send/SGDPDataResponse/SGDP"; private const string ctSGDPUpdateTenantMetadataEndPointctSGDPUpdateTenantMetadata = "/api/v1/link/send/SGDPUpdateTenantMetadata/SGDP"; private const string ctSGDPUpdateTenantMetadatactSGDPDataCommand = "SGDPUpdateTenantMetadataSGDPDataCommand"; private const string ctSGDPDataCommandctSGDPResponseDataCommand = "SGDPDataCommandSGDPResponseDataCommand"; private const string ctSGDPMaskCommandctSGDPMaskResponseEndPoint = "SGDPMaskCommand/api/v1/link/send/SGDPMaskResponse/SGDP"; private const string ctSGDPResponseDataCommandctSGDPMaskCommand = "SGDPResponseDataCommandSGDPMaskCommand"; private const string ctSGDPResponseMaskCommand = "SGDPResponseMaskCommand"; private const string ctSmartLinkSetupCommandctSGDPLogResponseEndPoint = "Setup/api/v1/link/send/SGDPLogsResponse/SGDP"; private const string ctSmartLinkUnSetupCommandctSGDPLogsCommand = "UnSetupSGDPLogsCommand"; publicprivate GlbSGDPPublisherMessageService(IRMSSmartLinkPublisherService smartLinkPublisherService, const string ctSGDPResponseLogCommand = "SGDPResponseLogsCommand"; IGlbSGDPResolverServiceprivate sgdpResolverService,const string ctSmartLinkSetupCommand = "setup"; private const string ctSmartLinkUnSetupCommand = "unSetup"; public GlbSGDPPublisherMessageService(IRMSSmartLinkPublisherService smartLinkPublisherService, IGlbSGDPResolverService sgdpResolverService, IRMSLogger logService) { _SmartLinkPublisherServicesmartLinkPublisherService = smartLinkPublisherService; _SGDPResolverServicesgdpResolverService = sgdpResolverService; _LogServicelogService = logService; } /// <summary> /// Adiciona uma mensagem de reposta para o comando "SGDPResponseDataCommand". /// </summary> /// <param name="parms"></param> public void AddResponseDataCommand(AddResponseDataCommandParms parms) { SmartLinkPublisherAddMessageParams parPublisher = new SmartLinkPublisherAddMessageParams(); parPublisher.{ Command = ctSGDPResponseDataCommand;, parPublisher.CorrelatedId = parms.CorrelatedId }; ; parPublisher.Data = parms.Message; parPublisher.RouterMessage = ctSGDPDataResponseEndPoint; _LogServicelogService.NotifyLogInfo(Properties.Resources.sconTotvsAppSGDPResponseDataCommandGravadoNaFila); _SmartLinkPublisherServicesmartLinkPublisherService.AddMessage(parPublisher); } /// <summary> /// Adiciona uma mensagem de reposta para o comando "SGDPResponseMaskCommand". /// </summary> /// <param name="parms"></param> public void AddResponseMaskCommand(AddResponseMaskCommandParms parms) { SmartLinkPublisherAddMessageParams parPublisher = new SmartLinkPublisherAddMessageParams(); { parPublisher.Command = ctSGDPResponseMaskCommand;, parPublisher. CorrelatedId = parms.CorrelatedId;, parPublisher.Data = parms.Message;, parPublisher.RouterMessage = ctSGDPMaskResponseEndPoint }; _LogServicelogService.NotifyLogInfo(Properties.Resources.sconTotvsAppSGDPResponseMaskCommandGravadoNaFila); _SmartLinkPublisherServicesmartLinkPublisherService.AddMessage(parPublisher); } /// <summary> /// Adiciona uma mensagem parade envioreposta depara umo comando de sgldpdateapplicationmetada"SGDPResponseLogCommand". /// </summary> /// <param name="parms">Parms</param> public void AddMessageUpdateTenantMetadataAddResponseLogCommand(AddMessageUpdateTenantMetadataParmsAddResponseLogCommandParms parms) { if (CanAddTenantMetadataMessage())SmartLinkPublisherAddMessageParams parPublisher = new SmartLinkPublisherAddMessageParams { try Command {= ctSGDPResponseLogCommand, List<string> jsonsCorrelatedId = GetUpdateTenandMetadata(parms.TenantId);CorrelatedId, Data foreach (string json in jsons)= parms.Message, RouterMessage = {ctSGDPLogResponseEndPoint }; SmartLinkPublisherAddMessageParams smartLinkParms = new SmartLinkPublisherAddMessageParams(_logService.NotifyLogInfo(Properties.Resources.sconTotvsAppSGDPResponseLogCommandGravadoNaFila); _smartLinkPublisherService.AddMessage(parPublisher); } smartLinkParms.Command = ctSGDPUpdateTenantMetadata; /// <summary> /// Adiciona uma mensagem para envio de um smartLinkParms.CorrelatedIdcomando = "";de sgldpdateapplicationmetada. /// </summary> public void smartLinkParms.Data = json;AddMessageUpdateTenantMetadata(AddMessageUpdateTenantMetadataParms parms) { if smartLinkParms.RouterMessage = ctSGDPUpdateTenantMetadataEndPoint; (CanAddTenantMetadataMessage()) { try _LogService.NotifyLogInfo(Properties.Resources.sconTotvsAppSGDPTenantMetadaGravadoNaFila);{ List<string> jsons = _SmartLinkPublisherService.AddMessage(smartLinkParmsGetUpdateTenandMetadata(parms.TenantId); } foreach (string json in jsons) } { catch (Exception ex) SmartLinkPublisherAddMessageParams { smartLinkParms = new SmartLinkPublisherAddMessageParams(); _LogService.NotifyLogWarning(ex, Properties.Resources.sconTotvsAppErroAoEnviarSGDPUpdateTenantMetadata)smartLinkParms.Command = ctSGDPUpdateTenantMetadata; } smartLinkParms.CorrelatedId = }""; } private bool CanAddTenantMetadataMessage() smartLinkParms.Data = {json; //Se existir alguma mensagem de sgdpsmartLinkParms.RouterMessage para= serctSGDPUpdateTenantMetadataEndPoint; processada, então não envia atualizaçaõ de medatdos pois esse processo é caro. _logService.NotifyLogInfo(Properties.Resources.sconTotvsAppSGDPTenantMetadaGravadoNaFila); var pendingMessages = _SmartLinkPublisherServicesmartLinkPublisherService.GetPendingMessagesAddMessage(smartLinkParms); List<SmartLinkMessageDataModel> messageUpstream = pendingMessages?.Messages?.Where( } y} => y.TypeEvent == ctSGDPUpdateTenantMetadata || catch (Exception ex) y.TypeEvent == ctSGDPDataCommand || { _logService.NotifyLogWarning(ex, Properties.Resources.sconTotvsAppErroAoEnviarSGDPUpdateTenantMetadata); y.TypeEvent == ctSGDPMaskCommand ||} } } y.TypeEvent ==private ctSGDPResponseDataCommand ||bool CanAddTenantMetadataMessage() { //Se existir alguma y.TypeEvent == ctSGDPResponseMaskCommand).ToList(); if (messageUpstream?.Count > 0)//Se existir alguma não inclua na fila..mensagem de sgdp para ser processada, então não envia atualizaçaõ de medatdos pois esse processo é caro. var pendingMessages return false= _smartLinkPublisherService.GetPendingMessages(); return true; List<SmartLinkMessageDataModel> messageUpstream = pendingMessages?.Messages?.Where( } y => private List<string> GetUpdateTenandMetadata(string tenantId) y.TypeEvent == ctSGDPUpdateTenantMetadata || { return _SGDPResolverService.GetSGDPTenantMetadata(y.TypeEvent == ctSGDPDataCommand || new MetadataTenantParms() { TenantIdy.TypeEvent == tenantIdctSGDPMaskCommand }|| )?.JsonsResult; } y.TypeEvent == ctSGDPResponseDataCommand public|| void AddMessageUnSetup() { var pendingMessagesy.TypeEvent == _SmartLinkPublisherServicectSGDPResponseMaskCommand).GetPendingMessagesToList(); List<SmartLinkMessageDataModel> messagesSGDP = pendingMessages?.Messages?.Where(y => y.TypeEvent.ToUpper() == ctSGDPUpdateTenantMetadata.ToUpper() &&if (messageUpstream?.Count > 0)//Se existir alguma não inclua na fila... return false; return true; } private List<string> GetUpdateTenandMetadata(string tenantId) { return _sgdpResolverService.GetSGDPTenantMetadata( y.TypeEvent.ToUpper new MetadataTenantParms() { =TenantId = ctSGDPDataCommand.ToUpper() && tenantId } )?.JsonsResult; } public void AddMessageUnSetup() { var pendingMessages = _smartLinkPublisherService.GetPendingMessages(); List<SmartLinkMessageDataModel> messagesSGDP = ypendingMessages?.TypeEvent.Messages?.Where(y => y.TypeEvent.ToUpper() == ctSGDPMaskCommandctSGDPUpdateTenantMetadata.ToUpper() && y.TypeEvent.ToUpper() == ctSGDPResponseDataCommandctSGDPDataCommand.ToUpper() && y.TypeEvent.ToUpper() == ctSGDPResponseMaskCommandctSGDPMaskCommand.ToUpper()).ToList(); && foreach (SmartLinkMessageDataModel model in messagesSGDP) _SmartLinkPublisherService.RemoveMessageById(model.Id); SmartLinkPublisherAddMessageParams parms = new SmartLinkPublisherAddMessageParams(); parms.Command = ctSmartLinkUnSetupCommand; parms.CorrelatedId = ""; parms.Datay.TypeEvent.ToUpper() == _SGDPResolverServicectSGDPLogsCommand.GetSGDPSetupToUpper().JsonResult; && _LogService.NotifyLogInfo(Properties.Resources.sconTotvsAppUnSetupGravadoNaFila); _SmartLinkPublisherService.AddMessage(parms); } public void AddMessageSetup() { SmartLinkPublisherAddMessageParams parms = new SmartLinkPublisherAddMessageParams(); parms.Command = ctSmartLinkSetupCommand; y.TypeEvent.ToUpper() == ctSGDPResponseDataCommand.ToUpper() && parms.CorrelatedId = ""; parms.Data = _SGDPResolverService.GetSGDPSetup().JsonResult; _LogService.NotifyLogInfo(Properties.Resources.sconTotvsAppSetupGravadoNaFila); _SmartLinkPublisherService.AddMessage(parms y.TypeEvent.ToUpper() == ctSGDPResponseMaskCommand.ToUpper()).ToList(); } if (messagesSGDP != null) } } |
04. Implementando um consumidor de mensagens
Para que uma classe seja um consumidor de mensagens no SmartLink, deve-se atender aos pré-requisitos listados abaixo:
Pré-requisitos
{
foreach (SmartLinkMessageDataModel model in messagesSGDP)
{
_smartLinkPublisherService.RemoveMessageById(model.Id);
}
}
SmartLinkPublisherAddMessageParams parms = new SmartLinkPublisherAddMessageParams
{
Command = ctSmartLinkUnSetupCommand,
CorrelatedId = "",
Data = _sgdpResolverService.GetSGDPSetup().JsonResult
};
_logService.NotifyLogInfo(Properties.Resources.sconTotvsAppUnSetupGravadoNaFila);
_smartLinkPublisherService.AddMessage(parms);
}
public void AddMessageSetup()
{
SmartLinkPublisherAddMessageParams parms = new SmartLinkPublisherAddMessageParams
{
Command = ctSmartLinkSetupCommand,
CorrelatedId = "",
Data = _sgdpResolverService.GetSGDPSetup().JsonResult
};
_logService.NotifyLogInfo(Properties.Resources.sconTotvsAppSetupGravadoNaFila);
_smartLinkPublisherService.AddMessage(parms);
}
}
} |
04. Implementando um consumidor de mensagens
Para que uma classe seja um consumidor de mensagens no SmartLink, deve-se atender aos pré-requisitos listados abaixo:
Pré-requisitos
- Criar um projeto (classLibrary .NET) na solution do segmento em questão, com o seguinte padrão de nome: RM.[Segmento].XXX.SmartLink.Service.
- Exemplo: RM.Glb.SGDP.SmartLink.Service.dll
- Adicionar referência para a dll "RM.Lib.SmartLink.dll";
Criar uma classe herdando da ancestral "RMSSmartLinkConsumerMessageBase".
- A classe "RMSSmartLinkConsumerMessageBase" herda da classe RMSObject da Lib. Consequentemente, as classes de "consumers" poderão chamar os métodos "CreateFacade" e "CreateModule" dentro de suas estruturas.
Carimbar a classe com o atributo "RMSSmartLinkConsumerMessageAttr". Nesse atributo, devem ser informados os dados abaixo:
Propriedade Descrição Cod.Sistema Identificador da aplicação Comando Nome do Comando da mensagem - Para realização de tratamento de exceções no caso de ocorrer erro no processamento da mensagem
Quando for considerado um erro e um nova tentativa de processamento deve ser realizada:
A classe RMSSmartLinkConsumerMessageException ou outra, pode ser utilizada.
Neste caso a mensagem será reenfileirada e novas tentativas de processamento serão realizadas.
Sendo considerado que a mensagem deve ser descartada, ou seja, esta mensagem não deve ser processada neste momento ou apenas sob intervenção manual:
A classe RMSSmartLinkConsumerFatalException, deverá ser utilizada e informado o motivo.
Neste caso a mensagem será colocada em um fila de espera (DLQ) e somente será reprocessada por uma intervenção manual ou será descartada. - Criar um projeto (classLibrary .NET) na solution do segmento em questão, com o seguinte padrão de nome: RM.[Segmento].XXX.SmartLink.Service.
- Exemplo: RM.Glb.SGDP.SmartLink.Service.dll
- Adicionar referência para a dll "RM.Lib.SmartLink.dll";
Criar uma classe herdando da ancestral "RMSSmartLinkConsumerMessageBase".
- A classe "RMSSmartLinkConsumerMessageBase" herda da classe RMSObject da Lib. Consequentemente, as classes de "consumers" poderão chamar os métodos "CreateFacade" e "CreateModule" dentro de suas estruturas.
Carimbar a classe com o atributo "RMSSmartLinkConsumerMessageAttr". Nesse atributo, devem ser informados os dados abaixo:
Propriedade Descrição Cod.Sistema Identificador da aplicação Comando Nome do Comando da mensagemCódigo fonte de exemplo (extraído da classe "GlbSGDPConsumerDataCommandMessage" localizada na solution de Globais, projeto "RM.Glb.SGDP.SmartLink.Service":
Bloco de código language c# firstline 1 linenumbers true using RM.Glb.SGDP.SmartLink.Service.Domain.Interfaces; using RM.Lib; using RM.Lib.SmartLink.Domain; using RM.Lib.SmartLink.Domain.Consumer; using RM.Lib.SmartLink.Domain.Interfaces; using RM.Lib.SmartLink.Domain.Publisher; using System; using System.Runtime.Serialization; namespace RM.Glb.SGDP.SmartLink.Service.Domain { /// <summary> /// Regras de implementação do mecanismo de processamento da mensagem SGDDataCommand do SGDP /// </summary> [RMSSmartLinkConsumerMessageAttr(CodSistema.Glb, "SGDPDataCommand")] public class GlbSGDPConsumerDataCommandMessage : RMSSmartLinkConsumerMessageBase { protected override ConsumerMessageExecuteResult DoExecute(string message) { logService.NotifyLogInfo(Properties.Resources.sconTotvsAppInicioExecucaoDoConsumerSGDPDataCommandConsumer); ConsumerMessageExecuteResult result = new ConsumerMessageExecuteResult(); IGlbSGDPResolverService resolver = GlbSGDPResolveFactory.NewSGDPResolve(this.DBS, this.logService); IRMSSmartLinkPublisherService smartLinkPublisherService = RMSSmartLinkPublisherFactory.NewSmartLinkPublisher(this.DBS, this.logService); IGlbSGDPPublisherMessageService publisher = new GlbSGDPPublisherMessageService(smartLinkPublisherServicethis.SmartLinkPublisherService, resolver, logService); ExecuteDataCommandParms par = new ExecuteDataCommandParms(); par.Message = message; try { var execDataResult = resolver.ExecuteSGDPDataCommand(par); logService.NotifyLogInfo(Properties.Resources.sconTotvsAppJSonSGDPDataResponseCommandForamGerados, "Quantidade JSons Gerados" Properties.Resources.sconTotvsAppQuantidadeDeJSonsGerados, execDataResult?.JsonResults?.Count); result.CorrelatedID = execDataResult.RequestId; if (execDataResult?.JsonResults != null) { foreach (var jsonResult in execDataResult.JsonResults) { AddResponseDataCommandParms parResponse = new AddResponseDataCommandParms(); parResponse.Message = jsonResult; parResponse.CorrelatedId = execDataResult.RequestId; publisher.AddResponseDataCommand(parResponse); } } } catch(Exception ex) { logService.NotifyLogError(new GlbSGDPConsumerDataCommandMessageException( Properties.Resources.sconTotvsAppErroAoProcessarSGDDataCommand, ex)); } logService.NotifyLogInfo(Properties.Resources.sconTotvsAppFimExecucaoDoConsumerSGDPDataCommandConsumer); return result; } } [Serializable] public class GlbSGDPConsumerDataCommandMessageException : RMSApplicationException { public GlbSGDPConsumerDataCommandMessageException() : base() { } public GlbSGDPConsumerDataCommandMessageException(string message) : base(message) { } public GlbSGDPConsumerDataCommandMessageException(string message, Exception ex) : base(message(message, ex, string.Empty) { } public GlbSGDPConsumerDataCommandMessageException(stringSerializationInfo messageinfo, ExceptionStreamingContext excontext) : base(messageinfo, ex, string.Emptycontext) { } public GlbSGDPConsumerDataCommandMessageException(SerializationInfo info, StreamingContext context) : base(info, context) { } } }
05. Diagrama de classes
06. DER
...
} }
05. Diagrama de classes
06. DER
Tabela | |
---|---|
GTOTVSLINKMESSAGE | Tabela utilizada para armazenar todos as mensagens geradas e enviadas para execução pelo SmartLink. Sempre que uma mensagem é executa com sucesso, a linha referente a mensagem é excluída dessa tabela , deixando essa tabela sempre leve. Esse procedimento melhora a performance do processo, visto que vários "updates" são realizados nessa tabela.Quando menor o volume de uma tabela, mais rápido será a operação do update. |
GTOTVSLINKMESSAGEEXEC | Tabela contendo todos os dados de execução de uma determinada mensagem. |
GTOTVSLINKLOG | Tabela contendo todos os logs de execução de uma mensagem. |