Removeu permissões na fila privada do MSMQ remoto e, mesmo assim, o Send não lança exceção? Este guia explica o porquê, mostra como confirmar falhas com ACK/NACK, e traz um passo a passo completo de diagnóstico, scripts e boas práticas para ambientes Windows/Windows Server.
Contexto do problema
Um cliente em um servidor Windows envia mensagens para uma fila privada do MSMQ hospedada em outro servidor, na mesma rede e domínio. Quando o computador‑cliente possui permissões completas na fila remota, envio e leitura funcionam normalmente. Ao remover essas permissões, esperava-se um erro imediato (por exemplo, “acesso negado”) ao chamar Send, porém a chamada retorna sem exceções aparentes. Por quê?
Como o MSMQ realmente funciona (e por que o Send não falha)
O MSMQ é assíncrono por design. A chamada Send não envia diretamente para a fila remota; ela coloca a mensagem em uma fila de saída local do serviço MSMQ no cliente. Depois, o serviço tenta a entrega ao destino em segundo plano. Se houver problemas de permissão, conectividade ou configuração, o erro pode ocorrer depois do retorno da sua chamada, e você só fica sabendo via:
- Mensagens de confirmação (acknowledgements, ou ACK/NACK) enviadas para uma fila de administração que você especifica; e/ou
- Filas de erros (Dead‑Letter / Trans. Dead‑Letter) e logs do Event Viewer.
Em outras palavras: Send “dá certo” localmente porque o serviço aceitou sua mensagem para processamento assíncrono — a falha efetiva (por exemplo, “sem permissão para gravar na fila remota”) surge após a tentativa de entrega, e não no momento do Send.
As causas mais prováveis e como atacar cada uma
| Possível causa | Explicação resumida | Como detectar | O que fazer |
|---|---|---|---|
| Cache de configuração do MSMQ | Após alterar permissões, o cliente/servidor pode ainda usar ACLs em cache. | Alterou ACL e o comportamento não mudou imediatamente. | Reinicie o serviço Message Queuing em ambos os hosts para forçar atualização. |
| Fila local × fila remota | O código, sem perceber, aponta para uma fila local com o mesmo nome. | Envios “sempre funcionam”, mesmo com ACLs remotas restritas. | Verifique o FormatName completo, garantindo que é remoto (ex.: FormatName:DIRECT=OS:SERVIDOR\private$\fila). |
| Alterações não aplicadas | As permissões não foram de fato gravadas/propagadas. | Ao reabrir propriedades, as ACLs não refletem as mudanças. | Confirme as ACLs, salve novamente e aguarde replicação do AD, se aplicável. |
| Modo “insecure” / políticas | Configurações que relaxam validações de segurança podem mascarar falhas. | Discrepância entre o esperado (acesso negado) e o observado. | Revise HKLM\SOFTWARE\Microsoft\MSMQ\Parameters\Security e políticas de grupo. |
| Credenciais do processo | O serviço/usuário de execução tem privilégios amplos (Domain Admin, LocalSystem, etc.). | Somente quando executa como “Admin” tudo parece funcionar. | Teste com uma conta padrão e identifique privilégios efetivos. |
| Firewalls e regras de serviço | Bloqueios de rede não geram exceção imediata no Send. | Entrega falha “silenciosamente” e há timeouts em segundo plano. | Confirme portas 1801/TCP, 2101–2108 e DCOM/RPC; habilite logs. |
| ACK/NACK ausentes | Sem ACK/NACK, você não enxerga as falhas pós‑Send. | Não há registros de chegada/recusa; DLQ cresce. | Ative ACK/NACK na mensagem e/ou monitore a DLQ/Journal para confirmação. |
Entendendo ACK/NACK no MSMQ (o “sinal vital” da entrega)
Para tornar a entrega observável, peça que o MSMQ envie mensagens de confirmação para uma fila de administração que você controla. Os tipos de confirmação mais úteis:
| Tipo | O que indica | Quando usar |
|---|---|---|
PositiveArrival | A mensagem chegou à fila de destino. | Para validar conectividade/ACLs de gravação. |
PositiveReceive | A mensagem foi recebida pela aplicação consumidora. | Para confirmar processamento no destino. |
NegativeArrival | Não foi possível alcançar a fila de destino. | Para diagnosticar DNS/firewall/ACL inexistente. |
NegativeReceive | A mensagem não foi recebida a tempo ou foi rejeitada. | Para detectar falhas no consumidor ou TTL curto. |
Dica: Ative também a DLQ (Dead‑Letter), pois mensagens não entregues/expiradas acabam lá. Para mensagens transacionais, a DLQ é a Transacional específica.
Diagnóstico passo a passo (playbook prático)
- Certifique-se do endereço remoto
UseFormatNameexplícito para uma fila remota privada:FormatName:DIRECT=OS:SERVIDOR\private$\minhaFila FormatName:DIRECT=TCP:10.0.0.10\private$\minhaFilaEvite caminhos ambíguos como.\private$\minhaFila(isso aponta para a máquina local). - Reinicie o serviço MSMQ nos dois extremos
Após mudanças de segurança/ACL, reinicie o serviço Message Queuing no cliente e no servidor hospedando a fila:sc stop MSMQ sc start MSMQ - Ative ACK/NACK e crie uma fila de administração local
Sem confirmações, você não verá os erros que ocorrem depois doSend. - Monitore Event Viewer
Verifique “Aplicativo” (origem: MSMQ) e, se disponível, “Aplicativos e Serviços → Microsoft → Windows → MSMQ”. - Cheque permissões efetivas
Teste com uma conta comum. Se possível, isole a conta de serviço do cliente para não herdar privilégios excessivos. - Revise firewall/rede
Garanta abertura das portas típicas (ex.: 1801/TCP; 2101–2108 conforme cenário) e DCOM/RPC, além de regras internas de inspeção. - Observe DLQ/Journal
Crescimento de DLQ ou ausência de registros no Journal dão pistas de falha de entrega/recebimento. - AD e replicação
Em ambientes com Active Directory, aguarde a replicação das mudanças de segurança entre controladores de domínio.
Exemplo em C#: enviando com ACK/NACK e verificando chegada
O exemplo abaixo usa System.Messaging (MSMQ) para enviar uma mensagem para uma fila privada remota usando FormatName e solicitar ACK/NACK para uma fila local de administração (que é automaticamente criada se não existir).
using System;
using System.Messaging;
class Program
{
static void Main()
{
// Fila de destino REMOTA (ajuste o host e o nome)
var destino = @"FormatName:DIRECT=OS:SERVIDOR\private$\minhaFila";
```
// Fila local para receber ACK/NACK (pode ser privada local)
var ackPath = @".\private$\ack_msmq";
if (!MessageQueue.Exists(ackPath))
{
MessageQueue.Create(ackPath, transactional: false);
}
using var destinoQ = new MessageQueue(destino);
using var ackQ = new MessageQueue(ackPath);
// Solicitar confirmações de chegada e de falhas
var msg = new Message
{
Body = "mensagem de diagnóstico",
Label = "diag-msmq",
Formatter = new BinaryMessageFormatter(),
AdministrationQueue = ackQ,
AcknowledgeType = AcknowledgeTypes.PositiveArrival
| AcknowledgeTypes.NegativeArrival
| AcknowledgeTypes.NegativeReceive
};
// (opcional) usar DLQ e TTL para enxergar falhas rapidamente
msg.UseDeadLetterQueue = true;
msg.TimeToReachQueue = TimeSpan.FromSeconds(30); // ajustar à sua rede
msg.TimeToBeReceived = TimeSpan.FromMinutes(2);
destinoQ.Send(msg); // pode "funcionar" localmente, mesmo com falha remota
// Ler o primeiro ACK/NACK recebido
ackQ.MessageReadPropertyFilter.SetAll();
try
{
var ack = ackQ.Receive(TimeSpan.FromSeconds(60));
Console.WriteLine($"ACK: {ack.Acknowledgment} - CorrelationId: {ack.CorrelationId}");
}
catch (MessageQueueException ex) when (ex.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout)
{
Console.WriteLine("Sem ACK/NACK em até 60s. Verifique rede/ACL/TTL.");
}
}
```
}
Interpretação: Se vier um PositiveArrival, a fila remota aceitou a mensagem (logo, você tinha permissão de escrita). Um NegativeArrival costuma indicar que a mensagem não chegou (bloqueio de rede, fila inexistente, permissão negada, etc.). Um NegativeReceive sugere que a aplicação consumidora não retirou a mensagem a tempo.
Exemplo em PowerShell: envio com ACK/NACK
# Executar no cliente
Add-Type -AssemblyName System.Messaging
$destino = "FormatName:DIRECT=OS:SERVIDOR\private$\minhaFila"
$ackPath = ".\private$\ack_msmq"
if (-not [System.Messaging.MessageQueue]::Exists($ackPath)) {
[System.Messaging.MessageQueue]::Create($ackPath) | Out-Null
}
$destQ = New-Object System.Messaging.MessageQueue $destino
$ackQ = New-Object System.Messaging.MessageQueue $ackPath
$msg = New-Object System.Messaging.Message
$msg.Body = "diagnostico"
$msg.Label = "diag-msmq"
$msg.Formatter = New-Object System.Messaging.BinaryMessageFormatter
$msg.AdministrationQueue = $ackQ
$msg.AcknowledgeType = [System.Messaging.AcknowledgeTypes]::PositiveArrival ` -bor [System.Messaging.AcknowledgeTypes]::NegativeArrival`
-bor [System.Messaging.AcknowledgeTypes]::NegativeReceive
$msg.UseDeadLetterQueue = $true
$msg.TimeToReachQueue = [TimeSpan]::FromSeconds(30)
$destQ.Send($msg)
$ackQ.MessageReadPropertyFilter.SetAll()
try {
$ack = $ackQ.Receive([TimeSpan]::FromSeconds(60))
"ACK: $($ack.Acknowledgment) CorrelationId: $($ack.CorrelationId)"
} catch {
"Sem ACK/NACK em 60s."
}
Checklist rápido de investigação
- Nome correto da fila: use
FormatName:DIRECT=OS:SERVIDOR\private$\filaouDIRECT=TCP:<ip>; confirme que não é.\private$. - Permissões mínimas: para enviar, a identidade do cliente precisa ao menos de WriteMessage. Para ler, ReceiveMessage/PeekMessage.
- Reinício do serviço: reinicie o MSMQ no cliente e no servidor após alterar ACLs.
- Portas/rede: verifique 1801/TCP (direct) e, conforme o cenário, 2101–2108 e DCOM/RPC.
- ACK/NACK: sempre habilite acknowledgements em cenários críticos ou de diagnóstico.
- DLQ/Journal: monitore as filas de erro e o journal para rastrear o ciclo de vida das mensagens.
- Event Viewer: procure por eventos do MSMQ no cliente e no servidor.
- Credenciais: teste execução com um usuário padrão (sem privilégios elevados).
- AD: leve em conta o tempo de replicação de permissões.
Diferenças entre fila privada e pública
Filas privadas não são publicadas no Active Directory; você sempre as referencia por FormatName (geralmente via DIRECT=...) ou PathName local (.\private$\...). Filas públicas podem ser resolvidas via AD. No problema em questão, a fila é privada e remota, o que reforça a importância de usar FormatName:DIRECT=... e de checar conectividade/ACL diretamente no host de destino.
Erros “silenciosos” comuns e como tornar visíveis
- Permissão insuficiente no destino: ative
PositiveArrival/NegativeArrival. Se vierNegativeArrival, a gravação não ocorreu. - Fila inexistente no destino:
NegativeArrival+ eventos no log do servidor. - Firewall/DNS:
NegativeArrivale/ou expiração do TimeToReachQueue com mensagem indo para DLQ. - Aplicação consumidora indisponível:
PositiveArrival(chegou) porémNegativeReceiveapós o TTL de recebimento.
Como confirmar “é realmente remoto”
Três verificações simples:
- Inspeção visual no código/config: procure por
DIRECT=OS:SERVIDOR\private$\filaouDIRECT=TCP:IP\private$\fila. Se houver.\private$, é local. - Desligue temporariamente o MSMQ do cliente: se o envio “funcionar” com o serviço desligado, você não está usando MSMQ local; se falhar de imediato, talvez referencie localmente.
- Crie uma fila local com o mesmo nome: se, ao criar
.\private$\fila, o comportamento do envio mudar, havia ambiguidade.
Políticas e registro que impactam segurança
Em alguns ambientes, políticas de segurança do MSMQ podem permitir comportamentos mais permissivos (por exemplo, cenários legados). Revise chaves sob HKLM\SOFTWARE\Microsoft\MSMQ\Parameters\Security e as GPOs aplicáveis. Alinhamento com os times de Segurança/Infra evita surpresas, principalmente quando máquinas legadas convivem com versões mais novas do Windows Server.
Scripts úteis para o dia a dia
Reiniciar o serviço MSMQ nos dois lados
Invoke-Command -ComputerName CLIENTE,SERVIDOR `
-ScriptBlock { sc stop MSMQ; sc start MSMQ }
Listar filas privadas locais (sanidade)
Get-ChildItem "HKLM:\SOFTWARE\Microsoft\MSMQ\Parameters\OCMsetup" | Out-Null
Em muitos servidores, você pode conferir rapidamente via MMC:
compmgmt.msc → Services and Applications → Message Queuing → Private Queues
Ver o crescimento da DLQ
# Caminhos padrão das DLQs do MSMQ:
.\System$;Deadletter (não transacional)
.\System$;Transactional dead-letter (transacional)
Add-Type -AssemblyName System.Messaging
$dlq = New-Object System.Messaging.MessageQueue ".\System$;Deadletter"
$dlq.GetAllMessages().Count
Boas práticas para ambientes de produção
- Padronize o uso de ACK/NACK em todas as integrações críticas. Trate a ausência de ACK como um incidente observável.
- Defina TTLs realistas (TimeToReachQueue e TimeToBeReceived): curtos o bastante para não gerar filas “zumbi”, longos o suficiente para a sua rede.
- Monitore DLQ e métricas (contagem por minuto, idade média de mensagens, etc.). Um spike na DLQ é sinal de problema.
- Segregue contas de serviço por aplicação e ambiente; evite admins desnecessários.
- Audite alterações de ACL em filas sensíveis. Documente quem pode Write/Receive.
- Automatize verificações (ex.: um job diário que envia um “ping” MSMQ e valida o
PositiveArrival).
FAQ rápido
“Por que eu nunca recebo exceção no Send?”
Porque o Send apenas enfileira localmente; a entrega real é assíncrona. Falhas aparecem via ACK/NACK, DLQ e logs.
“Consigo forçar uma validação imediata?”
Você pode abrir a fila explicitamente com as APIs nativas pedindo acesso de envio; se a infraestrutura recusar logo na abertura, você verá erro. Porém, em cenários remotos, boa parte das validações acontece no momento da entrega, e o método robusto continua sendo ACK/NACK + DLQ.
“A fila é transacional. Muda algo?”
Sim. Use transações ao enviar/receber e monitore a Transactional Dead‑Letter. Algumas propriedades (como DLQ não transacional) se comportam diferente.
“Uso .NET moderno. O System.Messaging ainda vale?”
O exemplo é voltado a Windows/Framework, onde MSMQ é tradicional. Em runtimes modernos no Windows, costuma-se usar interop ou serviços intermediários. O conceito de ACK/NACK e DLQ, contudo, permanece válido para o diagnóstico.
Modelo de decisão: o que observar primeiro
- Endereço: é remota via
DIRECT=...? - ACK: você está recebendo
PositiveArrivalou algumNegative*? - DLQ: cresceu após o teste?
- Event Viewer: há eventos de acesso negado/entrega falha?
- Rede: 1801/TCP (e 2101–2108/DCOM) liberados entre cliente e servidor?
- Credenciais: o processo cliente roda com privilégios além do esperado?
- Replicação: alterou ACL há pouco tempo em ambiente AD?
Resumo executivo
O Send do MSMQ “não falhar” após a remoção de permissões não é um bug; é consequência do modelo assíncrono. Para tornar falhas visíveis, peça ACK/NACK, monitore DLQ/Journal, e confira logs. Em paralelo, valide o FormatName remoto, reinicie o serviço após mudanças de ACL, e verifique portas/credenciais. Seguindo o playbook acima, você conseguirá identificar rapidamente se o problema é de permissão, endereço, rede ou consumo.
Passos práticos recomendados (recapitulação)
- Reinicie o serviço “Message Queuing” em ambos os hosts após alterar permissões.
- Use o Visualizador de Eventos (Aplicativo e MSMQ) para avisos/erros.
- Crie/automatize verificação de ACL por probe com ACK (C#/PowerShell).
- Teste com contas diferentes (usuário padrão vs. administrador).
- Ative confirmações (ACK/NACK) e DLQ; ajuste TTLs (TimeToReachQueue/TimeToBeReceived).
- Confirme FormatName remoto e regras de firewall/portas 1801, 2101–2108 e DCOM.
- Considere políticas/registro que afetam segurança (
...MSMQ\Parameters\Security).
Conclusão: ao entender que o Send apenas inicia a entrega, e ao instrumentar o fluxo com ACK/NACK + DLQ + logs, você transforma um “silêncio” enganoso em um processo observável e confiável, reduzindo o tempo de resolução e aumentando a segurança operacional.

