Redis, caches e estado operacional¶
Redis reúne caches reconstruíveis, contadores de quota/concorrência e locks. A perda desses dados tem efeitos diferentes: uma política pode ser recarregada, mas zerar um contador altera a admissão de requisições. Os padrões abaixo vêm dos produtores e consumidores; não descrevem instâncias corporativas.
Modelos visuais¶
Cache e invalidação¶
Caixas Redis mostram chave, tipo do valor e TTL; não são campos BSON nem novas collections.
Explorar diagramas detalhados com zoom
Legenda e convenções dos modelos. Os dicionários e evidências desta página permanecem a referência dos campos.
Políticas e configuração¶
%%{init: {"theme":"base","themeVariables":{"fontFamily":"Arial, sans-serif","fontSize":"16px","lineColor":"#64748b","primaryTextColor":"#172b4d"},"flowchart":{"htmlLabels":true,"useMaxWidth":true,"nodeSpacing":28,"rankSpacing":38,"padding":14,"curve":"linear","subGraphTitleMargin":{"top":12,"bottom":16}},"sequence":{"useMaxWidth":true,"actorMargin":28,"width":145,"height":45,"diagramMarginX":32,"diagramMarginY":12,"messageMargin":24,"wrap":true,"mirrorActors":false},"themeCSS":".edgeLabel, .edgeLabel p {background-color:var(--diagram-surface)!important;color:var(--diagram-text)!important}\n.cluster rect {fill:var(--diagram-group)!important;stroke:var(--diagram-line)!important}\n.cluster-label span, .cluster-label text {color:var(--diagram-text)!important;fill:var(--diagram-text)!important}\n.flowchart-link, .actor-line {stroke:var(--diagram-line)!important}\nmarker path {fill:var(--diagram-line)!important;stroke:var(--diagram-line)!important}\n.actor {fill:var(--diagram-domain)!important;stroke:var(--diagram-domain-border)!important}\ntext.actor, .messageText, .loopText, .labelText {fill:var(--diagram-text)!important}\n.messageLine0, .messageLine1, .loopLine {stroke:var(--diagram-line)!important}\n.labelBox {fill:var(--diagram-surface)!important;stroke:var(--diagram-line)!important}\n.note {fill:var(--diagram-async)!important;stroke:var(--diagram-async-border)!important}\n.noteText {fill:var(--diagram-text)!important}\n.nodeLabel, .nodeLabel p, .nodeLabel span {color:var(--diagram-text)!important}\n.node .nodeLabel, .node .nodeLabel p {font-size:17px;font-weight:600;line-height:1.4;text-align:center}\n.nodeLabel small {display:inline-block;margin-top:4px;font-size:15px;font-weight:400;line-height:1.4;color:var(--diagram-description)!important}\ntext.actor, text.actor tspan {font-size:17px;font-weight:600}\n.node.entry rect, .node.entry polygon, .node.entry path, .node.entry circle {fill:var(--diagram-entry)!important;stroke:var(--diagram-entry-border)!important}\n.node.domain rect, .node.domain polygon, .node.domain path, .node.domain circle {fill:var(--diagram-domain)!important;stroke:var(--diagram-domain-border)!important}\n.node.security rect, .node.security polygon, .node.security path, .node.security circle {fill:var(--diagram-security)!important;stroke:var(--diagram-security-border)!important}\n.node.store rect, .node.store polygon, .node.store path, .node.store circle {fill:var(--diagram-store)!important;stroke:var(--diagram-store-border)!important}\n.node.async rect, .node.async polygon, .node.async path, .node.async circle {fill:var(--diagram-async)!important;stroke:var(--diagram-async-border)!important}\n.node.external rect, .node.external polygon, .node.external path, .node.external circle {fill:var(--diagram-external)!important;stroke:var(--diagram-external-border)!important}\n text.actor tspan, .loopText tspan, .labelText tspan, .messageText tspan, .noteText tspan {fill:var(--diagram-text)!important}\n\n"}}%%
flowchart TB
builder["Builder<br/><small>Rotas e recursos iPaaS</small>"]:::domain
checker["Security Checker<br/><small>Autorizações e IPs</small>"]:::security
redis[("Redis<br/><small>Valores de configuração</small>")]:::store
invalidator["Cache Invalidator<br/><small>Remove chaves por entidade</small>"]:::async
builder -->|CacheUtil| redis
checker -->|JSON| redis
invalidator -->|KEYS / UNLINK| redis
classDef domain stroke-width:1.5px;
classDef security stroke-width:1.5px;
classDef store stroke-width:1.5px;
classDef async stroke-width:1.5px;
Laranja identifica armazenamento, verde processamento, roxo segurança e amarelo invalidação. As setas representam acesso ao cache, não referências entre documentos MongoDB.
| Padrão de chave | Escritor / leitor | Valor | TTL e invalidação |
|---|---|---|---|
{tenant}:route:{routeId} |
Builder | Configuração normalizada de client.core.Route |
CacheUtil da biblioteca; TTL não definido na chamada. Invalidação por entidade route |
{tenant}:resource:{resourceId} |
Builder | Recurso iPaaS normalizado | CacheUtil; invalidação por entidade |
{tenant}:environment:{environmentId} |
Builder | Ambiente iPaaS normalizado | CacheUtil; invalidação por entidade |
{tenant}:account:{accountId} |
Builder | Conta iPaaS normalizada; tipo CUSTOM não é armazenado nesse caminho | CacheUtil; invalidação por entidade |
{tenant}:integration:{integrationId} |
Builder | Diagrama iPaaS normalizado | 120 s explícitos. projectId pertence à consulta, mas não à chave |
{targetTenant}:authorization:{id} |
Security Checker | JSON com id, clientId, type, openIdUrl, header, validations conforme tipo |
Default 300 s; modo Redis ou memória. Invalidação authorization |
{targetTenant}:ip_policy:{id} |
Security Checker | JSON id, cidr[], kind |
Default 300 s; Redis ou memória. Invalidação ip_policy |
tenant-alias:{tenant} |
Global Registry / BFF | Alias textual | Escrita sem TTL explícito no chamador; delete e reconciliação periódica (default 5 min). BFF lê com timeout de 30 ms e omite alias na falha |
lock:tenant-alias-initial-load |
Global Registry | Token de lock pela biblioteca CacheStore | 30 s; liberação com token após carga inicial |
validations contém iss, issVal, aud, audVal, iat, exp, nbf. Os valores do Builder são modelos de cache/cliente, não collections de domínio. A serialização/TTL padrão do CacheUtil está na biblioteca compartilhada; não se deve inferir seu valor a partir do chamador.
Fontes: chaves Builder, adaptador iPaaS, modelo de rota, authorization cache, IP cache, aliases, BFF.
Identidade e tokens¶
| Serviço / chave | Valor e duração |
|---|---|
Auth Provider: token:{tenant}:{realm}:{app}:{group} |
Access token; segmentos vazios são omitidos pelo BuildKey. TTL expiresIn − 120 s; não grava quando o resultado não é positivo |
Auth Provider: {tenant}:token:{clientId}:{hash} |
Access token para client credentials; mesmo TTL. Hash: primeiros 16 bytes do SHA-256 de clientId + clientSecret, em hexadecimal |
Auth Provider: {tenant}:oidc:{hash(url)} |
JSON {issuer,jwksUrl}; default 5 min. Hash da URL em lowercase, SHA-256 truncado a 16 bytes |
Auth Provider: {tenant}:jwks:{hash(url)}:kid:{kid} |
JWK: kty, kid, use, alg, crv, n, e, x, y, x5c; default 5 min |
Security Checker: {tenant}:authorization:{authorizationId}:token:{hash} |
Token do caminho IssueToken; TTL expiresIn − 15 s |
| Security Checker: chave de token por app/group ou client | Padrões equivalentes ao Auth Provider; TTL expiresIn − 120 s no caminho geral |
O cliente de cache Go serializa valores em JSON, inclusive strings de token, e permite memória/Redis conforme configuração. Tokens e material de identidade não devem aparecer em exemplos com valores reais. A expiração é a principal renovação desses caches; invalidar uma autorização não equivale a revogar todos os tokens emitidos.
Fontes: Auth Provider tokens, OIDC/JWK, serialização, configuração, Checker tokens.
Contadores e exclusão mútua¶
%%{init: {"theme":"base","themeVariables":{"fontFamily":"Arial, sans-serif","fontSize":"16px","lineColor":"#64748b","primaryTextColor":"#172b4d"},"flowchart":{"htmlLabels":true,"useMaxWidth":true,"nodeSpacing":28,"rankSpacing":38,"padding":14,"curve":"linear","subGraphTitleMargin":{"top":12,"bottom":16}},"sequence":{"useMaxWidth":true,"actorMargin":28,"width":145,"height":45,"diagramMarginX":32,"diagramMarginY":12,"messageMargin":24,"wrap":true,"mirrorActors":false},"themeCSS":".edgeLabel, .edgeLabel p {background-color:var(--diagram-surface)!important;color:var(--diagram-text)!important}\n.cluster rect {fill:var(--diagram-group)!important;stroke:var(--diagram-line)!important}\n.cluster-label span, .cluster-label text {color:var(--diagram-text)!important;fill:var(--diagram-text)!important}\n.flowchart-link, .actor-line {stroke:var(--diagram-line)!important}\nmarker path {fill:var(--diagram-line)!important;stroke:var(--diagram-line)!important}\n.actor {fill:var(--diagram-domain)!important;stroke:var(--diagram-domain-border)!important}\ntext.actor, .messageText, .loopText, .labelText {fill:var(--diagram-text)!important}\n.messageLine0, .messageLine1, .loopLine {stroke:var(--diagram-line)!important}\n.labelBox {fill:var(--diagram-surface)!important;stroke:var(--diagram-line)!important}\n.note {fill:var(--diagram-async)!important;stroke:var(--diagram-async-border)!important}\n.noteText {fill:var(--diagram-text)!important}\n.nodeLabel, .nodeLabel p, .nodeLabel span {color:var(--diagram-text)!important}\n.node .nodeLabel, .node .nodeLabel p {font-size:17px;font-weight:600;line-height:1.4;text-align:center}\n.nodeLabel small {display:inline-block;margin-top:4px;font-size:15px;font-weight:400;line-height:1.4;color:var(--diagram-description)!important}\ntext.actor, text.actor tspan {font-size:17px;font-weight:600}\n.node.entry rect, .node.entry polygon, .node.entry path, .node.entry circle {fill:var(--diagram-entry)!important;stroke:var(--diagram-entry-border)!important}\n.node.domain rect, .node.domain polygon, .node.domain path, .node.domain circle {fill:var(--diagram-domain)!important;stroke:var(--diagram-domain-border)!important}\n.node.security rect, .node.security polygon, .node.security path, .node.security circle {fill:var(--diagram-security)!important;stroke:var(--diagram-security-border)!important}\n.node.store rect, .node.store polygon, .node.store path, .node.store circle {fill:var(--diagram-store)!important;stroke:var(--diagram-store-border)!important}\n.node.async rect, .node.async polygon, .node.async path, .node.async circle {fill:var(--diagram-async)!important;stroke:var(--diagram-async-border)!important}\n.node.external rect, .node.external polygon, .node.external path, .node.external circle {fill:var(--diagram-external)!important;stroke:var(--diagram-external-border)!important}\n text.actor tspan, .loopText tspan, .labelText tspan, .messageText tspan, .noteText tspan {fill:var(--diagram-text)!important}\n\n"}}%%
flowchart TB
scheduler["Scheduler<br/><small>Inicializa e repõe quotas</small>"]:::domain
quota[("Redis · ratelimit<br/><small>Saldo inteiro por atividade</small>")]:::store
checker["Security Checker<br/><small>Consulta e decrementa saldo</small>"]:::security
scheduler -->|SETNX / SET / DEL| quota
checker -->|KEYS / GET / DECR| quota
classDef domain stroke-width:1.5px;
classDef security stroke-width:1.5px;
classDef store stroke-width:1.5px;
| Chave | Dono / operações | Expiração e atomicidade |
|---|---|---|
{tenant}:ratelimit:{activityId} |
Scheduler inicializa com SETNX, repõe com SET e remove com DEL. Valor inteiro maxRequests. Checker procura *:ratelimit:{id}, escolhe primeiro resultado, GET e DECR |
Sem TTL declarado. GET/decisão/DECR são comandos separados; busca wildcard não seleciona tenant explicitamente |
{tenant}:{concurrencyKey} (default concurrent_requests) |
Broker lê saldo concorrente, verifica limite e INCR; na conclusão DECR, corrigindo valor negativo com INCR | Sem TTL declarado; admissão não é uma operação atômica conjunta. Falhas Redis permitem prosseguir |
rate-limit:{tenant}:{bucket} |
BFF: contador inteiro, Lua INCR e EXPIRE na primeira ocorrência | Janela default 60 s, limite default 5. Script agrupa incremento/expiração; falha retorna contagem zero |
scheduler:http-call:lock:{id} |
Scheduler: token UUID, SET NX PX; liberação Lua compare-and-delete | Timeout da chamada + padding (default 5 s); usado para política CRON/SKIP |
O Rate Limit Mongo descreve a política; a atividade Scheduler controla reposição; a chave Redis representa saldo. IDs são correlacionados por contratos HTTP, não por relacionamento físico. Exclusão de cache indiscriminada também remove estado operacional.
Fontes: quota Scheduler, operações de saldo, consumo Checker, Broker, bucket BFF, lock HTTP.
Invalidação e caches em memória¶
Cache Invalidator constrói {tenant}:{entity}:{id}; segmentos não informados podem se tornar curingas. Usa KEYS e UNLINK. Eventos iPaaS sem tenant podem alcançar múltiplos tenants. A invalidação HTTP com tenant também publica evento para consumidores. O script Cache Monitor possui recuperação ampla com FLUSHALL e limpeza do Discovery; esse comportamento não representa invalidação seletiva.
| Serviço | Cache em memória | Renovação / limite |
|---|---|---|
| Discovery | Mapa de rotas agrupado por tenant | Invalida tenant por mensagem; limpa tudo na desconexão do consumidor; sem TTL de rota |
| Auth Provider | JWKS por realm, separado do cache OIDC/JWK anterior | TTL 5 min, max stale 1 h; limpeza periódica 5 min |
| Broker | JWKS | TTL 1 h |
| Web Pages | Caffeine openapi-doc-cache |
Expiração após escrita de 3 min |
| Auth Provider / Security Checker | Backend alternativo de cache em memória | TTL dos respectivos clientes; estado não compartilhado entre processos |
Fontes: invalidador, monitor, Discovery, JWKS Auth Provider, Web Pages.
Riscos de concorrência, abrangência de chaves e retenção estão separados em Análises de dados.