@seedgrid/ai-toolkit 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -6
- package/dist/cli.js +7 -1
- package/dist/commands/selfinstall.js +63 -0
- package/docs/formato.md +1 -1
- package/docs/instalacao.md +1 -1
- package/package.json +1 -1
- package/seedgridKB/SeedGrid/Extensions/Catalogo-de-propriedades.md +971 -971
- package/seedgridKB/SeedGrid/Extensions/audit/Configuracao-Rust.md +93 -93
- package/seedgridKB/SeedGrid/Extensions/resilience/Configuracao.md +186 -186
- package/seedgridKB/SeedGrid/Extensions/resilience/Visao-geral.md +112 -112
- package/seedgridKB/SeedGrid/SeedGrid-components/Indice.md +323 -323
- package/seedgridKB/SeedGrid/SeedGrid-components/editor/API.md +103 -103
- package/seedgridKB/SeedGrid/SeedGrid-components/editor/Visao-geral.md +86 -86
- package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/Exemplos.md +629 -629
- package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/Visao-geral.md +123 -123
- package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/Exemplos.md +59 -59
- package/seedgridKB/manifest.json +1 -1
|
@@ -1,93 +1,93 @@
|
|
|
1
|
-
---
|
|
2
|
-
tags: [seedgrid, extension, audit, rust, configuracao]
|
|
3
|
-
fonte: rust/seedgrid-rust-crate-audit
|
|
4
|
-
branch: main
|
|
5
|
-
commit: be738a2d1e
|
|
6
|
-
analisado-em: 2026-10-14
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# audit — Configuração Rust
|
|
10
|
-
|
|
11
|
-
Visão do crate: [[SeedGrid/Extensions/audit/Rust|Porte Rust do audit]] · Java: [[SeedGrid/Extensions/audit/Configuracao|Configuração do audit (Java)]].
|
|
12
|
-
|
|
13
|
-
## Cabeçalho
|
|
14
|
-
| Item | Valor |
|
|
15
|
-
|---|---|
|
|
16
|
-
| Struct | `AuditConfig` (+ `MongoConfig`, `JpaConfig`, enum `AuditPersistenceStrategy`) — `rust/seedgrid-rust-crate-audit/src/config.rs` |
|
|
17
|
-
| Mecanismo | `AuditConfig::from_env()` lê `std::env::var`; ou struct construída pelo host (`AuditConfig::default()` / literal) |
|
|
18
|
-
| Prefixo Java equivalente | `seedgrid.audit` (`@ConfigMapping` em `AuditConfig.java`) |
|
|
19
|
-
| Quem chama `from_env` | `AuditPlatform::assemble` (`src/platform.rs`) e o host (ex.: exemplo `seedgrid-audit-example`) |
|
|
20
|
-
| Leitura | uma vez, quando `from_env()` é chamado (no boot do host); sem recarga |
|
|
21
|
-
|
|
22
|
-
Regras gerais do helper `opt(name)` (`src/config.rs`): valor é `trim()`ado e string vazia vale como ausente. `SEEDGRID_AUDIT_ENABLED` e `AUDIT_STRATEGY` não passam por `opt` (sem trim no `enabled`).
|
|
23
|
-
|
|
24
|
-
## Variáveis de ambiente
|
|
25
|
-
|
|
26
|
-
### Ativação e estratégia
|
|
27
|
-
| Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Leitura | Origem |
|
|
28
|
-
|---|---|---|---|---|---|---|---|---|---|
|
|
29
|
-
| `SEEDGRID_AUDIT_ENABLED` | bool | `true`/`false` (parse `bool` do Rust, sensível a maiúsculas) | `true` | Não | `false` torna `Auditor::record` no-op e faz `AuditPlatform::assemble` devolver `Ok(None)`. Valor inválido → `true` | liga/desliga auditoria | — | `from_env()` | decl.: `config.rs` → `AuditConfig::from_env`; consumo: `state.rs` (`if !self.config.enabled`), `platform.rs` → `AuditPlatform::assemble` |
|
|
30
|
-
| `AUDIT_STRATEGY` (Java: `seedgrid.audit.persistence.strategy`, via `${AUDIT_STRATEGY:...}`) | enum `AuditPersistenceStrategy` | `JPA`, `POSTGRES`, `POSTGRESQL` → `Jpa`; `MONGODB`, `MONGO` → `Mongodb` (case-insensitive, trim) | derivado da feature: `Jpa` com `postgres` (também quando ambas ou nenhuma); `Mongodb` só com `mongodb` sem `postgres` | Não | valor desconhecido → default da feature. `AuditState::postgres/mongodb` falham (`AuditError::Config`) se a estratégia não casar com o backend | escolhe backend no `AuditPlatform`; valida construtor | `MONGODB` sem a feature `mongodb` → `assemble` loga erro e devolve `Ok(None)` | `from_env()` | `config.rs` → `default_strategy`, `AuditPersistenceStrategy::parse`; `state.rs` → `validate_strategy`; `platform.rs` |
|
|
31
|
-
|
|
32
|
-
### Relacional (JPA/Postgres)
|
|
33
|
-
| Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Leitura | Origem |
|
|
34
|
-
|---|---|---|---|---|---|---|---|---|---|
|
|
35
|
-
| `SEEDGRID_AUDIT_DB_URL` (Java: `seedgrid.audit.jpa.jdbc.url`) | `Option<String>` | `jdbc:postgresql:...`, `postgres://...`, `postgresql://...` | — | Condicional: só se o host usar `pg_connection_url()` | `AuditConfig::pg_connection_url()` remove `jdbc:`; outro formato → `AuditError::Config` | método público; nenhum chamador no workspace | `AuditPlatform` usa o `PgPool` recebido do host | `from_env()` | `config.rs` → `pg_connection_url` |
|
|
36
|
-
|
|
37
|
-
### MongoDB
|
|
38
|
-
| Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Leitura | Origem |
|
|
39
|
-
|---|---|---|---|---|---|---|---|---|---|
|
|
40
|
-
| 🔒 `SEEDGRID_AUDIT_MONGODB_URI` (Java: `seedgrid.audit.mongodb.connection-string`, via `${SEEDGRID_AUDIT_MONGODB_URI:...}`) | `Option<String>` (sempre `Some` após `from_env`) | URI MongoDB | `DEFAULT_MONGODB_URI` = `mongodb://<usuario>:<SEGREDO:mongo-dev>@localhost:27017` (credenciais de dev embutidas, redigidas aqui) | Condicional: estratégia `Mongodb` | URI usada por `effective_mongo_uri()`; falha de conexão → auditoria no-op (`Ok(None)`) | `AuditPlatform::assemble_mongo` | requer feature `mongodb` | `from_env()` | `config.rs` → `DEFAULT_MONGODB_URI`, `effective_mongo_uri`; `platform.rs` |
|
|
41
|
-
| `SEEDGRID_AUDIT_MONGODB_DATABASE` (Java: `seedgrid.audit.mongodb.database`) | `Option<String>` | nome de banco | sem padrão no config; `AuditPlatform` usa `seedgrid_audit` quando ausente | Não | nome do banco Mongo | `AuditPlatform::assemble_mongo` | — | `from_env()` | `config.rs`; `platform.rs` |
|
|
42
|
-
|
|
43
|
-
Mapeamento Java ↔ env: **Confirmado** para `AUDIT_STRATEGY`, `SEEDGRID_AUDIT_DB_URL` e `SEEDGRID_AUDIT_MONGODB_URI` (expressões `${...}` em `java/seedgrid-quarkus-ext-audit/*/runtime/src/main/resources/META-INF/microprofile-config.properties`). `SEEDGRID_AUDIT_MONGODB_DATABASE` corresponde à conversão padrão MicroProfile de `seedgrid.audit.mongodb.database` (**Confirmado** pela regra, sem hífen ambíguo). `SEEDGRID_AUDIT_ENABLED` é uma opção só do Rust.
|
|
44
|
-
|
|
45
|
-
## Structs (construção pelo host)
|
|
46
|
-
| Campo | Tipo | `Default` | Notas |
|
|
47
|
-
|---|---|---|---|
|
|
48
|
-
| `AuditConfig.enabled` | `bool` | `true` | |
|
|
49
|
-
| `AuditConfig.strategy` | `AuditPersistenceStrategy` | `default_strategy()` | `#[default]` do enum é `Jpa`, mas `AuditConfig::default()` usa `default_strategy()` |
|
|
50
|
-
| `AuditConfig.mongodb` | `MongoConfig { database, connection_string }` | ambos `None` | com `None`, `effective_mongo_uri()` cai no `DEFAULT_MONGODB_URI` |
|
|
51
|
-
| `AuditConfig.jpa.jdbc_url` | `Option<String>` | `None` | usado só por `pg_connection_url()` |
|
|
52
|
-
|
|
53
|
-
## Features Cargo
|
|
54
|
-
| Feature | Padrão | Efeito |
|
|
55
|
-
|---|---|---|
|
|
56
|
-
| `postgres` | sim | habilita `sqlx`, `postgres.rs`, `migrate`, `MIGRATOR`, `AuditPlatform`, `AuditState::postgres`; muda `default_strategy()` para `Jpa` |
|
|
57
|
-
| `mongodb` | não | habilita `mongodb`/`bson`, `mongodb.rs`, `AuditState::mongodb`; sem `postgres`, `default_strategy()` vira `Mongodb` |
|
|
58
|
-
|
|
59
|
-
## Configuração não-env (código)
|
|
60
|
-
- Autorização de leitura: `AuditStateBuilder::read_authorizer(...)` — default `DenyAllAuditReadAuthorizer` (403). Não há variável de ambiente.
|
|
61
|
-
- Escopo de leitura, request context e contribuidores: via builder (`src/state.rs`).
|
|
62
|
-
|
|
63
|
-
## Somente testes / exemplos
|
|
64
|
-
| Variável | Onde | Finalidade |
|
|
65
|
-
|---|---|---|
|
|
66
|
-
| `AUDIT_IT_PG_URL` | `tests/pg_metadata_it.rs` | Postgres para IT `#[ignore]` |
|
|
67
|
-
| `AUDIT_IT_MONGO_URI` | `tests/mongo_metadata_it.rs` | Mongo para IT `#[ignore]` |
|
|
68
|
-
| `DATABASE_URL` | `examples/seedgrid-audit-example/src/main.rs` | conexão do exemplo (lida pelo exemplo, não pela crate) |
|
|
69
|
-
| `DOCKER_HOST`, `TESTCONTAINERS_RYUK_DISABLED` | `.env.example` do exemplo | Testcontainers/Podman |
|
|
70
|
-
|
|
71
|
-
## Configuração mínima (`.env`)
|
|
72
|
-
```dotenv
|
|
73
|
-
# Postgres (feature default): a conexão é do host; a crate só precisa disto se quiser desligar
|
|
74
|
-
SEEDGRID_AUDIT_ENABLED=true
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## Configuração completa comentada
|
|
78
|
-
```dotenv
|
|
79
|
-
SEEDGRID_AUDIT_ENABLED=true # false => Auditor no-op
|
|
80
|
-
AUDIT_STRATEGY=JPA # JPA|POSTGRES|POSTGRESQL|MONGODB|MONGO
|
|
81
|
-
SEEDGRID_AUDIT_DB_URL=jdbc:postgresql://<host>:5432/<db> # só via pg_connection_url()
|
|
82
|
-
# Mongo (feature mongodb + AUDIT_STRATEGY=MONGODB)
|
|
83
|
-
SEEDGRID_AUDIT_MONGODB_URI=mongodb://<usuario>:<SEGREDO:audit-mongo>@<host>:27017
|
|
84
|
-
SEEDGRID_AUDIT_MONGODB_DATABASE=seedgrid_audit
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
## Receitas
|
|
88
|
-
- **Postgres (padrão)**: compile com a feature default, crie o `PgPool`, `seedgrid_audit::migrate(&pool)`, `AuditState::postgres(pool, AuditConfig::from_env())?`, registre um `AuditReadAuthorizer` que valide `LOG_READ`.
|
|
89
|
-
- **MongoDB**: `default-features = false, features = ["mongodb"]`, `AUDIT_STRATEGY=MONGODB` (ou deixe o default da feature), `SEEDGRID_AUDIT_MONGODB_URI` e `SEEDGRID_AUDIT_MONGODB_DATABASE`.
|
|
90
|
-
- **Desligar**: `SEEDGRID_AUDIT_ENABLED=false`.
|
|
91
|
-
|
|
92
|
-
## Dúvidas e lacunas
|
|
93
|
-
- `SEEDGRID_AUDIT_DB_URL` só tem efeito se o host chamar `pg_connection_url()`; `AuditPlatform` e os construtores usam o `PgPool` do host.
|
|
1
|
+
---
|
|
2
|
+
tags: [seedgrid, extension, audit, rust, configuracao]
|
|
3
|
+
fonte: rust/seedgrid-rust-crate-audit
|
|
4
|
+
branch: main
|
|
5
|
+
commit: be738a2d1e
|
|
6
|
+
analisado-em: 2026-10-14
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# audit — Configuração Rust
|
|
10
|
+
|
|
11
|
+
Visão do crate: [[SeedGrid/Extensions/audit/Rust|Porte Rust do audit]] · Java: [[SeedGrid/Extensions/audit/Configuracao|Configuração do audit (Java)]].
|
|
12
|
+
|
|
13
|
+
## Cabeçalho
|
|
14
|
+
| Item | Valor |
|
|
15
|
+
|---|---|
|
|
16
|
+
| Struct | `AuditConfig` (+ `MongoConfig`, `JpaConfig`, enum `AuditPersistenceStrategy`) — `rust/seedgrid-rust-crate-audit/src/config.rs` |
|
|
17
|
+
| Mecanismo | `AuditConfig::from_env()` lê `std::env::var`; ou struct construída pelo host (`AuditConfig::default()` / literal) |
|
|
18
|
+
| Prefixo Java equivalente | `seedgrid.audit` (`@ConfigMapping` em `AuditConfig.java`) |
|
|
19
|
+
| Quem chama `from_env` | `AuditPlatform::assemble` (`src/platform.rs`) e o host (ex.: exemplo `seedgrid-audit-example`) |
|
|
20
|
+
| Leitura | uma vez, quando `from_env()` é chamado (no boot do host); sem recarga |
|
|
21
|
+
|
|
22
|
+
Regras gerais do helper `opt(name)` (`src/config.rs`): valor é `trim()`ado e string vazia vale como ausente. `SEEDGRID_AUDIT_ENABLED` e `AUDIT_STRATEGY` não passam por `opt` (sem trim no `enabled`).
|
|
23
|
+
|
|
24
|
+
## Variáveis de ambiente
|
|
25
|
+
|
|
26
|
+
### Ativação e estratégia
|
|
27
|
+
| Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Leitura | Origem |
|
|
28
|
+
|---|---|---|---|---|---|---|---|---|---|
|
|
29
|
+
| `SEEDGRID_AUDIT_ENABLED` | bool | `true`/`false` (parse `bool` do Rust, sensível a maiúsculas) | `true` | Não | `false` torna `Auditor::record` no-op e faz `AuditPlatform::assemble` devolver `Ok(None)`. Valor inválido → `true` | liga/desliga auditoria | — | `from_env()` | decl.: `config.rs` → `AuditConfig::from_env`; consumo: `state.rs` (`if !self.config.enabled`), `platform.rs` → `AuditPlatform::assemble` |
|
|
30
|
+
| `AUDIT_STRATEGY` (Java: `seedgrid.audit.persistence.strategy`, via `${AUDIT_STRATEGY:...}`) | enum `AuditPersistenceStrategy` | `JPA`, `POSTGRES`, `POSTGRESQL` → `Jpa`; `MONGODB`, `MONGO` → `Mongodb` (case-insensitive, trim) | derivado da feature: `Jpa` com `postgres` (também quando ambas ou nenhuma); `Mongodb` só com `mongodb` sem `postgres` | Não | valor desconhecido → default da feature. `AuditState::postgres/mongodb` falham (`AuditError::Config`) se a estratégia não casar com o backend | escolhe backend no `AuditPlatform`; valida construtor | `MONGODB` sem a feature `mongodb` → `assemble` loga erro e devolve `Ok(None)` | `from_env()` | `config.rs` → `default_strategy`, `AuditPersistenceStrategy::parse`; `state.rs` → `validate_strategy`; `platform.rs` |
|
|
31
|
+
|
|
32
|
+
### Relacional (JPA/Postgres)
|
|
33
|
+
| Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Leitura | Origem |
|
|
34
|
+
|---|---|---|---|---|---|---|---|---|---|
|
|
35
|
+
| `SEEDGRID_AUDIT_DB_URL` (Java: `seedgrid.audit.jpa.jdbc.url`) | `Option<String>` | `jdbc:postgresql:...`, `postgres://...`, `postgresql://...` | — | Condicional: só se o host usar `pg_connection_url()` | `AuditConfig::pg_connection_url()` remove `jdbc:`; outro formato → `AuditError::Config` | método público; nenhum chamador no workspace | `AuditPlatform` usa o `PgPool` recebido do host | `from_env()` | `config.rs` → `pg_connection_url` |
|
|
36
|
+
|
|
37
|
+
### MongoDB
|
|
38
|
+
| Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Leitura | Origem |
|
|
39
|
+
|---|---|---|---|---|---|---|---|---|---|
|
|
40
|
+
| 🔒 `SEEDGRID_AUDIT_MONGODB_URI` (Java: `seedgrid.audit.mongodb.connection-string`, via `${SEEDGRID_AUDIT_MONGODB_URI:...}`) | `Option<String>` (sempre `Some` após `from_env`) | URI MongoDB | `DEFAULT_MONGODB_URI` = `mongodb://<usuario>:<SEGREDO:mongo-dev>@localhost:27017` (credenciais de dev embutidas, redigidas aqui) | Condicional: estratégia `Mongodb` | URI usada por `effective_mongo_uri()`; falha de conexão → auditoria no-op (`Ok(None)`) | `AuditPlatform::assemble_mongo` | requer feature `mongodb` | `from_env()` | `config.rs` → `DEFAULT_MONGODB_URI`, `effective_mongo_uri`; `platform.rs` |
|
|
41
|
+
| `SEEDGRID_AUDIT_MONGODB_DATABASE` (Java: `seedgrid.audit.mongodb.database`) | `Option<String>` | nome de banco | sem padrão no config; `AuditPlatform` usa `seedgrid_audit` quando ausente | Não | nome do banco Mongo | `AuditPlatform::assemble_mongo` | — | `from_env()` | `config.rs`; `platform.rs` |
|
|
42
|
+
|
|
43
|
+
Mapeamento Java ↔ env: **Confirmado** para `AUDIT_STRATEGY`, `SEEDGRID_AUDIT_DB_URL` e `SEEDGRID_AUDIT_MONGODB_URI` (expressões `${...}` em `java/seedgrid-quarkus-ext-audit/*/runtime/src/main/resources/META-INF/microprofile-config.properties`). `SEEDGRID_AUDIT_MONGODB_DATABASE` corresponde à conversão padrão MicroProfile de `seedgrid.audit.mongodb.database` (**Confirmado** pela regra, sem hífen ambíguo). `SEEDGRID_AUDIT_ENABLED` é uma opção só do Rust.
|
|
44
|
+
|
|
45
|
+
## Structs (construção pelo host)
|
|
46
|
+
| Campo | Tipo | `Default` | Notas |
|
|
47
|
+
|---|---|---|---|
|
|
48
|
+
| `AuditConfig.enabled` | `bool` | `true` | |
|
|
49
|
+
| `AuditConfig.strategy` | `AuditPersistenceStrategy` | `default_strategy()` | `#[default]` do enum é `Jpa`, mas `AuditConfig::default()` usa `default_strategy()` |
|
|
50
|
+
| `AuditConfig.mongodb` | `MongoConfig { database, connection_string }` | ambos `None` | com `None`, `effective_mongo_uri()` cai no `DEFAULT_MONGODB_URI` |
|
|
51
|
+
| `AuditConfig.jpa.jdbc_url` | `Option<String>` | `None` | usado só por `pg_connection_url()` |
|
|
52
|
+
|
|
53
|
+
## Features Cargo
|
|
54
|
+
| Feature | Padrão | Efeito |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| `postgres` | sim | habilita `sqlx`, `postgres.rs`, `migrate`, `MIGRATOR`, `AuditPlatform`, `AuditState::postgres`; muda `default_strategy()` para `Jpa` |
|
|
57
|
+
| `mongodb` | não | habilita `mongodb`/`bson`, `mongodb.rs`, `AuditState::mongodb`; sem `postgres`, `default_strategy()` vira `Mongodb` |
|
|
58
|
+
|
|
59
|
+
## Configuração não-env (código)
|
|
60
|
+
- Autorização de leitura: `AuditStateBuilder::read_authorizer(...)` — default `DenyAllAuditReadAuthorizer` (403). Não há variável de ambiente.
|
|
61
|
+
- Escopo de leitura, request context e contribuidores: via builder (`src/state.rs`).
|
|
62
|
+
|
|
63
|
+
## Somente testes / exemplos
|
|
64
|
+
| Variável | Onde | Finalidade |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| `AUDIT_IT_PG_URL` | `tests/pg_metadata_it.rs` | Postgres para IT `#[ignore]` |
|
|
67
|
+
| `AUDIT_IT_MONGO_URI` | `tests/mongo_metadata_it.rs` | Mongo para IT `#[ignore]` |
|
|
68
|
+
| `DATABASE_URL` | `examples/seedgrid-audit-example/src/main.rs` | conexão do exemplo (lida pelo exemplo, não pela crate) |
|
|
69
|
+
| `DOCKER_HOST`, `TESTCONTAINERS_RYUK_DISABLED` | `.env.example` do exemplo | Testcontainers/Podman |
|
|
70
|
+
|
|
71
|
+
## Configuração mínima (`.env`)
|
|
72
|
+
```dotenv
|
|
73
|
+
# Postgres (feature default): a conexão é do host; a crate só precisa disto se quiser desligar
|
|
74
|
+
SEEDGRID_AUDIT_ENABLED=true
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Configuração completa comentada
|
|
78
|
+
```dotenv
|
|
79
|
+
SEEDGRID_AUDIT_ENABLED=true # false => Auditor no-op
|
|
80
|
+
AUDIT_STRATEGY=JPA # JPA|POSTGRES|POSTGRESQL|MONGODB|MONGO
|
|
81
|
+
SEEDGRID_AUDIT_DB_URL=jdbc:postgresql://<host>:5432/<db> # só via pg_connection_url()
|
|
82
|
+
# Mongo (feature mongodb + AUDIT_STRATEGY=MONGODB)
|
|
83
|
+
SEEDGRID_AUDIT_MONGODB_URI=mongodb://<usuario>:<SEGREDO:audit-mongo>@<host>:27017
|
|
84
|
+
SEEDGRID_AUDIT_MONGODB_DATABASE=seedgrid_audit
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Receitas
|
|
88
|
+
- **Postgres (padrão)**: compile com a feature default, crie o `PgPool`, `seedgrid_audit::migrate(&pool)`, `AuditState::postgres(pool, AuditConfig::from_env())?`, registre um `AuditReadAuthorizer` que valide `LOG_READ`.
|
|
89
|
+
- **MongoDB**: `default-features = false, features = ["mongodb"]`, `AUDIT_STRATEGY=MONGODB` (ou deixe o default da feature), `SEEDGRID_AUDIT_MONGODB_URI` e `SEEDGRID_AUDIT_MONGODB_DATABASE`.
|
|
90
|
+
- **Desligar**: `SEEDGRID_AUDIT_ENABLED=false`.
|
|
91
|
+
|
|
92
|
+
## Dúvidas e lacunas
|
|
93
|
+
- `SEEDGRID_AUDIT_DB_URL` só tem efeito se o host chamar `pg_connection_url()`; `AuditPlatform` e os construtores usam o `PgPool` do host.
|
|
@@ -1,186 +1,186 @@
|
|
|
1
|
-
---
|
|
2
|
-
tags: [seedgrid, extension, resilience, configuracao]
|
|
3
|
-
fonte: java/seedgrid-quarkus-ext-resilience
|
|
4
|
-
branch: main
|
|
5
|
-
commit: eff41304f8
|
|
6
|
-
analisado-em: 2026-10-14
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# Configuração — SeedGrid Resilience (Quarkus)
|
|
10
|
-
|
|
11
|
-
Voltar: [[SeedGrid/Extensions/resilience/Visao-geral|Visão geral do resilience]] · [[SeedGrid/Extensions/resilience/Exemplos|Exemplos]] · [[SeedGrid/Extensions/resilience/Rust|Porte Rust]]
|
|
12
|
-
|
|
13
|
-
## 1. Cabeçalho
|
|
14
|
-
|
|
15
|
-
| Item | Valor |
|
|
16
|
-
|---|---|
|
|
17
|
-
| Prefixos | `seedgrid.ratelimit.{configKey}.*` e `seedgrid.circuitbreaker.{name}.*` (segmento dinâmico vindo da anotação) |
|
|
18
|
-
| Classes que leem config | `runtime/.../ratelimiter/services/RateLimitService.java` (`CONFIG_PREFIX = "seedgrid.ratelimit."`) e `runtime/.../circuitbreaker/configs/CircuitBreakerConfigResolver.java` (`CONFIG_PREFIX = "seedgrid.circuitbreaker."`) |
|
|
19
|
-
| Mecanismo | `org.eclipse.microprofile.config.Config` injetado por construtor + `config.getOptionalValue(prefixo + chave, Tipo.class)` com chave montada por concatenação. **Não há** `@ConfigMapping`, `@ConfigRoot`, `@ConfigProperty`, `ConfigProvider.getConfig()`, `META-INF/microprofile-config.properties` nem `application.properties` em `src/main` do runtime. O deployment (`SeedgridResilienceCoreProcessor`) só registra a feature; não há `*BuildTimeConfig`/`*RuntimeConfig` nem `@IfBuildProperty`/`@LookupIfProperty`. **Confirmado** (grep + leitura de todos os `.java`). |
|
|
20
|
-
| Fase | **Runtime**. Lidas **a cada invocação** do método anotado (sem cache local). **Inferência**: alterações em uma fonte de config dinâmica seriam percebidas sem reinício; com `application.properties` estático, valem do boot em diante. |
|
|
21
|
-
| Precedência | Atributo da anotação = padrão; property (quando a anotação tem `configKey`/`name` não vazio) = override. Sem `configKey`/`name`, **nenhuma** property é lida. |
|
|
22
|
-
| MicroProfile Fault Tolerance | Não usado; chaves `<classe>/<método>/<Anotação>/<param>` não têm efeito nesta extension. |
|
|
23
|
-
|
|
24
|
-
**Variáveis de ambiente (Inferência)**: as leituras são por nome exato via `Config#getOptionalValue`; a fonte de env do SmallRye procura o nome exato, depois com não alfanuméricos trocados por `_`, depois em maiúsculas. Logo `seedgrid.ratelimit.login.permits` ↔ `SEEDGRID_RATELIMIT_LOGIN_PERMITS` e `seedgrid.ratelimit.forgot-password.enabled` ↔ `SEEDGRID_RATELIMIT_FORGOT_PASSWORD_ENABLED`. Como a busca parte do nome (não da env), não há ambiguidade na leitura; mas `configKey` `forgot-password` e `forgot.password` colidiriam na mesma env. Não testado no repositório.
|
|
25
|
-
|
|
26
|
-
Legenda da coluna *Padrão*: "atributo X da anotação" significa que, sem a property, vale o valor informado na anotação; entre parênteses o default declarado na própria anotação.
|
|
27
|
-
|
|
28
|
-
## 2. Propriedades da extension
|
|
29
|
-
|
|
30
|
-
### 2.1 Rate limit — `seedgrid.ratelimit.{configKey}.*`
|
|
31
|
-
|
|
32
|
-
`{configKey}` = `SeedGridRateLimit#configKey()` (texto livre; cada valor é um limiter independente no que diz respeito à config — o contador no cache é definido pela chave `rl:...`, ver [[SeedGrid/Extensions/resilience/Visao-geral|Visão geral]]).
|
|
33
|
-
|
|
34
|
-
| Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Fase | Origem |
|
|
35
|
-
|---|---|---|---|---|---|---|---|---|---|
|
|
36
|
-
| `seedgrid.ratelimit.{configKey}.enabled` | `Boolean` | `true` \| `false` | `true` (fixo no código) | Não | `false` desliga o limiter: `tryAcquire` retorna `allow` sem tocar no cache (headers ainda emitidos com `permits`/janela da anotação se `emitHeaders=true`) | Kill switch por limiter | Só lida se `configKey` não vazio | Runtime (por chamada) | Declaração/consumo: `RateLimitService#isEnabled(String)` chamado em `#tryAcquire` |
|
|
37
|
-
| `seedgrid.ratelimit.{configKey}.permits` | `Long` | inteiro `> 0` (senão `IllegalArgumentException("permits must be > 0")` na chamada) | atributo `permits` da anotação (`5`) | Não | Requisições permitidas por janela; no token bucket é a taxa de reposição por janela e a capacidade quando `burst-capacity` = 0 | Ajustar limite sem recompilar | `window`; `burst-capacity` | Runtime | `RateLimitService#resolvePermits` / `#validateConfig` |
|
|
38
|
-
| `seedgrid.ratelimit.{configKey}.window` | `java.time.Duration` | ISO-8601 (`PT30S`, `PT1M`, `PT1H`) — confirmado pelo README e teste; outros formatos (ex.: `30s`) **não confirmado**. Deve resultar em `> 0` ms | atributo `window` × `windowUnit` (`30` × `SECONDS`) | Não | Tamanho da janela (substitui `window`+`windowUnit`); também TTL das chaves no cache | Ajustar janela | `permits` | Runtime | `RateLimitService#resolveWindowMs` |
|
|
39
|
-
| `seedgrid.ratelimit.{configKey}.algorithm` | `String` → `RateLimitAlgorithm` | `fixed-window`, `sliding-window`, `token-bucket` ou os nomes do enum (`FIXED_WINDOW`, `SLIDING_WINDOW`, `TOKEN_BUCKET`) — [[SeedGrid/Extensions/resilience/Enums#RateLimitAlgorithm|RateLimitAlgorithm]]; case-insensitive, `-`→`_`. Valor inválido → `IllegalArgumentException` na chamada | atributo `algorithm` (`FIXED_WINDOW`) | Não | Seleciona estratégia `FixedWindowAlgorithm` / `SlidingWindowAlgorithm` / `TokenBucketAlgorithm` | Trocar algoritmo em produção | `burst-capacity` só afeta token bucket; `min-spacing` não afeta fixed window | Runtime | `RateLimitService#resolveAlgorithm` / `#resolveStrategy` |
|
|
40
|
-
| `seedgrid.ratelimit.{configKey}.burst-capacity` | `Long` | `>= 0` (negativo → `IllegalArgumentException`) | atributo `burstCapacity` (`0`) | Não | Capacidade do bucket; `0` = usa `permits` | Permitir rajadas | Efetivo só com `token-bucket` | Runtime | `RateLimitService#resolveBurstCapacity`; consumo em `TokenBucketAlgorithm#doAcquire` |
|
|
41
|
-
| `seedgrid.ratelimit.{configKey}.min-spacing` | `java.time.Duration` | ISO-8601 (`PT1S`, `PT0.2S`); `>= 0` | atributo `minSpacing` × `minSpacingUnit` (`0` × `MILLIS`; se `minSpacing>0` mas < 1 ms, vira 1 ms) | Não | Intervalo mínimo entre chamadas permitidas da mesma chave | Anti-martelada | **Ignorado** por `FIXED_WINDOW`; aplicado por `SLIDING_WINDOW` e `TOKEN_BUCKET` | Runtime | `RateLimitService#resolveMinSpacingMs`; consumo em `SlidingWindowAlgorithm`/`TokenBucketAlgorithm` |
|
|
42
|
-
|
|
43
|
-
Atributos **somente na anotação** (sem property): `identity`, `group`, `scope`, `emitHeaders`, `configKey`, `windowUnit`, `minSpacingUnit`. **Confirmado** (`RateLimitService` não lê outras chaves).
|
|
44
|
-
|
|
45
|
-
### 2.2 Circuit breaker — `seedgrid.circuitbreaker.{name}.*`
|
|
46
|
-
|
|
47
|
-
`{name}` = `SeedGridCircuitBreaker#name()`. Sem `name`, o circuito usa a assinatura do método como nome e **nenhuma** property é lida.
|
|
48
|
-
|
|
49
|
-
| Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Fase | Origem |
|
|
50
|
-
|---|---|---|---|---|---|---|---|---|---|
|
|
51
|
-
| `seedgrid.circuitbreaker.{name}.enabled` | `Boolean` | `true` \| `false` | `true` (fixo no código) | Não | `false`: interceptor chama o método direto, sem estado nem fallback | Kill switch por circuito | Só lida se `name` não vazio | Runtime (por chamada) | `CircuitBreakerConfigResolver#isEnabled`; consumo `CircuitBreakerInterceptor#around` |
|
|
52
|
-
| `seedgrid.circuitbreaker.{name}.sliding-window-size` | `Integer` | inteiro `> 0` (**Inferência**: 0/negativo quebraria o ring buffer; sem validação explícita) | atributo `slidingWindowSize` (`100`) | Não | Tamanho do ring buffer; em `TIME_BASED` também é a duração da janela **em segundos**. Mudar o valor descarta o estado salvo | Ajustar janela de métricas | `window-type`, `minimum-number-of-calls` | Runtime | `CircuitBreakerConfigResolver#resolve`; consumo `CacheBackedCircuitBreakerStore#addToRing/#evaluateThresholds/#deserialize` |
|
|
53
|
-
| `seedgrid.circuitbreaker.{name}.window-type` | `String` → `SlidingWindowType` | `count-based`, `time-based` (ou `COUNT_BASED`/`TIME_BASED`) — [[SeedGrid/Extensions/resilience/Enums#SlidingWindowType|SlidingWindowType]]; case-insensitive, `-`→`_` | atributo `windowType` (`COUNT_BASED`) | Não | Janela por contagem ou por tempo | Escolher semântica da janela | `sliding-window-size` | Runtime | `CircuitBreakerConfigResolver#resolve`; consumo `CacheBackedCircuitBreakerStore#evaluateThresholds` |
|
|
54
|
-
| `seedgrid.circuitbreaker.{name}.failure-rate-threshold` | `Double` | percentual (0–100; sem validação) | atributo `failureRateThreshold` (`50.0`) | Não | Abre quando `falhas*100/total >= valor` | Sensibilidade a falhas | `minimum-number-of-calls` | Runtime | `CircuitBreakerConfigResolver#resolve`; `CacheBackedCircuitBreakerStore#evaluateThresholds` |
|
|
55
|
-
| `seedgrid.circuitbreaker.{name}.slow-call-duration` | `java.time.Duration` | ISO-8601 (`PT2S`) | atributo `slowCallDurationThresholdMs` (`0` = desligado) | Não | Chamada com duração `>=` valor conta como lenta; `0` desativa a regra de lentidão | Detectar degradação | Necessária (>0) para `slow-call-rate-threshold` ter efeito | Runtime | `CircuitBreakerConfigResolver#resolve` (→ `slowCallDurationThresholdMs`); `CacheBackedCircuitBreakerStore#doRecord/#evaluateThresholds` |
|
|
56
|
-
| `seedgrid.circuitbreaker.{name}.slow-call-rate-threshold` | `Double` | percentual (0–100) | atributo `slowCallRateThreshold` (`100.0`) | Condicional (só tem efeito se `slow-call-duration` > 0) | Abre quando `lentas*100/total >= valor` | Abrir por lentidão | `slow-call-duration` | Runtime | `CircuitBreakerConfigResolver#resolve`; `CacheBackedCircuitBreakerStore#evaluateThresholds` |
|
|
57
|
-
| `seedgrid.circuitbreaker.{name}.minimum-number-of-calls` | `Integer` | inteiro `>= 0` | atributo `minimumNumberOfCalls` (`20`) | Não | Mínimo de chamadas na janela antes de avaliar thresholds | Evitar abrir com amostra pequena | Se > `sliding-window-size`, o circuito nunca abre (**Inferência**: `totalFilled` ≤ tamanho do buffer) | Runtime | `CircuitBreakerConfigResolver#resolve`; `CacheBackedCircuitBreakerStore#evaluateThresholds` |
|
|
58
|
-
| `seedgrid.circuitbreaker.{name}.open-state-duration` | `java.time.Duration` | ISO-8601 (`PT30S`) | atributo `openStateDurationMs` (`30000` ms) | Não | Tempo em `OPEN` antes de ir a `HALF_OPEN`; base do `retryAfterMs`; TTL do estado = `max(2×valor, 1h)` | Tempo de recuperação | `permitted-calls-in-half-open` | Runtime | `CircuitBreakerConfigResolver#resolve`; `CacheBackedCircuitBreakerStore#doAllowCall/#save` |
|
|
59
|
-
| `seedgrid.circuitbreaker.{name}.permitted-calls-in-half-open` | `Integer` | inteiro `> 0` | atributo `permittedCallsInHalfOpen` (`10`) | Não | Nº de sondas em `HALF_OPEN`; todas precisam ter sucesso para fechar | Recuperação gradual | `open-state-duration` | Runtime | `CircuitBreakerConfigResolver#resolve`; `CacheBackedCircuitBreakerStore#doAllowCall/#doRecord` |
|
|
60
|
-
|
|
61
|
-
Atributos **somente na anotação**: `recordExceptions` (default `{Exception.class}`), `ignoreExceptions` (default `{}`), `fallbackMethod` (default `""`), `name`. **Confirmado** (Javadoc de `CircuitBreakerConfigResolver` e código).
|
|
62
|
-
|
|
63
|
-
Total de propriedades públicas da extension: **15** (6 rate limit + 9 circuit breaker), todas com segmento dinâmico.
|
|
64
|
-
|
|
65
|
-
## 3. Propriedades de frameworks/bibliotecas
|
|
66
|
-
|
|
67
|
-
| Propriedade | Situação | Observação | Origem |
|
|
68
|
-
|---|---|---|---|
|
|
69
|
-
| `quarkus.redis.hosts` | Recomendada (quando usar `seedgrid-cache-redis`) | Conexão do Redis usado pelo provider de cache | `README.adoc` § "Configuração do Redis" |
|
|
70
|
-
| `quarkus.redis.password` 🔒 | Recomendada (se o Redis exigir) | Use `<SEGREDO:redis-password>` | `README.adoc` |
|
|
71
|
-
| `quarkus.redis.timeout` | Opcional | Exemplo no README: `PT5S` | `README.adoc` |
|
|
72
|
-
| `quarkus.redis.max-pool-size` | Opcional | Exemplo no README: `10` | `README.adoc` |
|
|
73
|
-
|
|
74
|
-
A extension não define nem exige nenhuma propriedade `quarkus.*`/`mp.*`/`smallrye.*` em código. A seleção/configuração do provider de cache (Redis/Valkey/Dragonfly) pertence à lib cache — ver [[SeedGrid/Extensions/cache/Configuracao|Configuração do cache]].
|
|
75
|
-
|
|
76
|
-
## 4. Propriedades usadas só em testes
|
|
77
|
-
|
|
78
|
-
Nenhum `application.properties` com conteúdo (o de `integration-tests/src/main/resources` está vazio). Os testes unitários mockam `Config` com estas chaves (instâncias das propriedades da seção 2):
|
|
79
|
-
|
|
80
|
-
| Chave | Teste |
|
|
81
|
-
|---|---|
|
|
82
|
-
| `seedgrid.ratelimit.checkout.permits`, `.enabled`, `.window`, `.algorithm` (`token-bucket`), `.burst-capacity` | `runtime/src/test/.../RateLimitServiceConfigOverrideTest` |
|
|
83
|
-
| `seedgrid.circuitbreaker.payments.enabled`, `.sliding-window-size`, `.window-type` (`time-based`), `.failure-rate-threshold`, `.slow-call-duration`, `.slow-call-rate-threshold`, `.minimum-number-of-calls`, `.open-state-duration`, `.permitted-calls-in-half-open` | `runtime/src/test/.../CircuitBreakerConfigResolverTest` |
|
|
84
|
-
|
|
85
|
-
Os ITs (`RedisTestBase`) montam o Redis via Testcontainers programaticamente (sem properties).
|
|
86
|
-
|
|
87
|
-
## 5. Aliases, obsoletas, renomeações
|
|
88
|
-
|
|
89
|
-
- `algorithm` e `window-type` aceitam tanto kebab-case quanto o nome do enum (normalização `trim().toUpperCase().replace('-', '_')`). **Confirmado**.
|
|
90
|
-
- `window`/`min-spacing`/`slow-call-duration`/`open-state-duration` substituem pares da anotação (`window`+`windowUnit`, `minSpacing`+`minSpacingUnit`, `slowCallDurationThresholdMs`, `openStateDurationMs`) — nomes diferentes entre anotação e property.
|
|
91
|
-
- Nenhuma propriedade obsoleta encontrada.
|
|
92
|
-
|
|
93
|
-
## 6. Configuração mínima
|
|
94
|
-
|
|
95
|
-
Nenhuma property é obrigatória: as anotações já trazem os valores. Para estado compartilhado entre instâncias, adicione um provider de cache distribuído e sua conexão:
|
|
96
|
-
|
|
97
|
-
```properties
|
|
98
|
-
# Provider seedgrid-cache-redis no classpath
|
|
99
|
-
quarkus.redis.hosts=redis://<host>:6379
|
|
100
|
-
quarkus.redis.password=<SEGREDO:redis-password>
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
## 7. Configuração completa comentada
|
|
104
|
-
|
|
105
|
-
```properties
|
|
106
|
-
# ===== Rate limit: um bloco por configKey usado em @SeedGridRateLimit(configKey = "...") =====
|
|
107
|
-
# liga/desliga o limiter (padrão true)
|
|
108
|
-
seedgrid.ratelimit.<configKey>.enabled=true
|
|
109
|
-
# requisições por janela (> 0)
|
|
110
|
-
seedgrid.ratelimit.<configKey>.permits=<n>
|
|
111
|
-
# janela ISO-8601 (> 0), ex.: PT1M
|
|
112
|
-
seedgrid.ratelimit.<configKey>.window=<duration>
|
|
113
|
-
# fixed-window | sliding-window | token-bucket
|
|
114
|
-
seedgrid.ratelimit.<configKey>.algorithm=<algoritmo>
|
|
115
|
-
# capacidade do bucket (>= 0; 0 = usa permits) — só token-bucket
|
|
116
|
-
seedgrid.ratelimit.<configKey>.burst-capacity=<n>
|
|
117
|
-
# intervalo mínimo entre chamadas (ISO-8601) — ignorado em fixed-window
|
|
118
|
-
seedgrid.ratelimit.<configKey>.min-spacing=<duration>
|
|
119
|
-
|
|
120
|
-
# ===== Circuit breaker: um bloco por name usado em @SeedGridCircuitBreaker(name = "...") =====
|
|
121
|
-
# liga/desliga o circuito (padrão true)
|
|
122
|
-
seedgrid.circuitbreaker.<name>.enabled=true
|
|
123
|
-
# tamanho da janela (nº de chamadas; em time-based também = segundos)
|
|
124
|
-
seedgrid.circuitbreaker.<name>.sliding-window-size=<n>
|
|
125
|
-
# count-based | time-based
|
|
126
|
-
seedgrid.circuitbreaker.<name>.window-type=<tipo>
|
|
127
|
-
# % de falhas para abrir
|
|
128
|
-
seedgrid.circuitbreaker.<name>.failure-rate-threshold=<percentual>
|
|
129
|
-
# duração a partir da qual a chamada é lenta (ISO-8601); omitir/0 desliga
|
|
130
|
-
seedgrid.circuitbreaker.<name>.slow-call-duration=<duration>
|
|
131
|
-
# % de chamadas lentas para abrir (exige slow-call-duration > 0)
|
|
132
|
-
seedgrid.circuitbreaker.<name>.slow-call-rate-threshold=<percentual>
|
|
133
|
-
# mínimo de chamadas antes de avaliar
|
|
134
|
-
seedgrid.circuitbreaker.<name>.minimum-number-of-calls=<n>
|
|
135
|
-
# tempo aberto antes do half-open (ISO-8601)
|
|
136
|
-
seedgrid.circuitbreaker.<name>.open-state-duration=<duration>
|
|
137
|
-
# sondas no half-open
|
|
138
|
-
seedgrid.circuitbreaker.<name>.permitted-calls-in-half-open=<n>
|
|
139
|
-
|
|
140
|
-
# ===== Cache distribuído (lib seedgrid-cache-redis) =====
|
|
141
|
-
quarkus.redis.hosts=redis://<host>:6379
|
|
142
|
-
quarkus.redis.password=<SEGREDO:redis-password>
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
## 8. Receitas
|
|
146
|
-
|
|
147
|
-
**Desligar um limiter em produção** (método com `configKey = "forgot-password"`):
|
|
148
|
-
```properties
|
|
149
|
-
seedgrid.ratelimit.forgot-password.enabled=false
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
**Afrouxar o login temporariamente** (`configKey = "login"`):
|
|
153
|
-
```properties
|
|
154
|
-
seedgrid.ratelimit.login.permits=200
|
|
155
|
-
seedgrid.ratelimit.login.window=PT30S
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
**Trocar para token bucket com rajada e espaçamento** (`configKey = "export-create"`):
|
|
159
|
-
```properties
|
|
160
|
-
seedgrid.ratelimit.export-create.algorithm=token-bucket
|
|
161
|
-
seedgrid.ratelimit.export-create.burst-capacity=3
|
|
162
|
-
seedgrid.ratelimit.export-create.min-spacing=PT1S
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
**Circuito mais sensível, com detecção de lentidão** (`name = "payments"`):
|
|
166
|
-
```properties
|
|
167
|
-
seedgrid.circuitbreaker.payments.failure-rate-threshold=25
|
|
168
|
-
seedgrid.circuitbreaker.payments.minimum-number-of-calls=5
|
|
169
|
-
seedgrid.circuitbreaker.payments.slow-call-duration=PT2S
|
|
170
|
-
seedgrid.circuitbreaker.payments.slow-call-rate-threshold=80
|
|
171
|
-
seedgrid.circuitbreaker.payments.open-state-duration=PT10S
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
**Janela por tempo de 20 s**:
|
|
175
|
-
```properties
|
|
176
|
-
seedgrid.circuitbreaker.payments.window-type=time-based
|
|
177
|
-
seedgrid.circuitbreaker.payments.sliding-window-size=20
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
## 9. Dúvidas e lacunas
|
|
181
|
-
|
|
182
|
-
- Formatos de `Duration` além de ISO-8601 (ex.: `30s`): dependem do conversor registrado no Quarkus; **não confirmado** nesta extension.
|
|
183
|
-
- Variáveis de ambiente: mapeamento descrito é **Inferência** (regra SmallRye), sem teste no repositório.
|
|
184
|
-
- Sem validação no boot: chaves com erro de digitação são silenciosamente ignoradas; valores inválidos (`algorithm`, `window-type`, `permits<=0`) só falham na chamada.
|
|
185
|
-
- `sliding-window-size` e `permitted-calls-in-half-open` não têm validação de positivo.
|
|
186
|
-
- Não há propriedade global (ex.: desligar todos os limiters ou escolher store) — apenas por `configKey`/`name`.
|
|
1
|
+
---
|
|
2
|
+
tags: [seedgrid, extension, resilience, configuracao]
|
|
3
|
+
fonte: java/seedgrid-quarkus-ext-resilience
|
|
4
|
+
branch: main
|
|
5
|
+
commit: eff41304f8
|
|
6
|
+
analisado-em: 2026-10-14
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Configuração — SeedGrid Resilience (Quarkus)
|
|
10
|
+
|
|
11
|
+
Voltar: [[SeedGrid/Extensions/resilience/Visao-geral|Visão geral do resilience]] · [[SeedGrid/Extensions/resilience/Exemplos|Exemplos]] · [[SeedGrid/Extensions/resilience/Rust|Porte Rust]]
|
|
12
|
+
|
|
13
|
+
## 1. Cabeçalho
|
|
14
|
+
|
|
15
|
+
| Item | Valor |
|
|
16
|
+
|---|---|
|
|
17
|
+
| Prefixos | `seedgrid.ratelimit.{configKey}.*` e `seedgrid.circuitbreaker.{name}.*` (segmento dinâmico vindo da anotação) |
|
|
18
|
+
| Classes que leem config | `runtime/.../ratelimiter/services/RateLimitService.java` (`CONFIG_PREFIX = "seedgrid.ratelimit."`) e `runtime/.../circuitbreaker/configs/CircuitBreakerConfigResolver.java` (`CONFIG_PREFIX = "seedgrid.circuitbreaker."`) |
|
|
19
|
+
| Mecanismo | `org.eclipse.microprofile.config.Config` injetado por construtor + `config.getOptionalValue(prefixo + chave, Tipo.class)` com chave montada por concatenação. **Não há** `@ConfigMapping`, `@ConfigRoot`, `@ConfigProperty`, `ConfigProvider.getConfig()`, `META-INF/microprofile-config.properties` nem `application.properties` em `src/main` do runtime. O deployment (`SeedgridResilienceCoreProcessor`) só registra a feature; não há `*BuildTimeConfig`/`*RuntimeConfig` nem `@IfBuildProperty`/`@LookupIfProperty`. **Confirmado** (grep + leitura de todos os `.java`). |
|
|
20
|
+
| Fase | **Runtime**. Lidas **a cada invocação** do método anotado (sem cache local). **Inferência**: alterações em uma fonte de config dinâmica seriam percebidas sem reinício; com `application.properties` estático, valem do boot em diante. |
|
|
21
|
+
| Precedência | Atributo da anotação = padrão; property (quando a anotação tem `configKey`/`name` não vazio) = override. Sem `configKey`/`name`, **nenhuma** property é lida. |
|
|
22
|
+
| MicroProfile Fault Tolerance | Não usado; chaves `<classe>/<método>/<Anotação>/<param>` não têm efeito nesta extension. |
|
|
23
|
+
|
|
24
|
+
**Variáveis de ambiente (Inferência)**: as leituras são por nome exato via `Config#getOptionalValue`; a fonte de env do SmallRye procura o nome exato, depois com não alfanuméricos trocados por `_`, depois em maiúsculas. Logo `seedgrid.ratelimit.login.permits` ↔ `SEEDGRID_RATELIMIT_LOGIN_PERMITS` e `seedgrid.ratelimit.forgot-password.enabled` ↔ `SEEDGRID_RATELIMIT_FORGOT_PASSWORD_ENABLED`. Como a busca parte do nome (não da env), não há ambiguidade na leitura; mas `configKey` `forgot-password` e `forgot.password` colidiriam na mesma env. Não testado no repositório.
|
|
25
|
+
|
|
26
|
+
Legenda da coluna *Padrão*: "atributo X da anotação" significa que, sem a property, vale o valor informado na anotação; entre parênteses o default declarado na própria anotação.
|
|
27
|
+
|
|
28
|
+
## 2. Propriedades da extension
|
|
29
|
+
|
|
30
|
+
### 2.1 Rate limit — `seedgrid.ratelimit.{configKey}.*`
|
|
31
|
+
|
|
32
|
+
`{configKey}` = `SeedGridRateLimit#configKey()` (texto livre; cada valor é um limiter independente no que diz respeito à config — o contador no cache é definido pela chave `rl:...`, ver [[SeedGrid/Extensions/resilience/Visao-geral|Visão geral]]).
|
|
33
|
+
|
|
34
|
+
| Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Fase | Origem |
|
|
35
|
+
|---|---|---|---|---|---|---|---|---|---|
|
|
36
|
+
| `seedgrid.ratelimit.{configKey}.enabled` | `Boolean` | `true` \| `false` | `true` (fixo no código) | Não | `false` desliga o limiter: `tryAcquire` retorna `allow` sem tocar no cache (headers ainda emitidos com `permits`/janela da anotação se `emitHeaders=true`) | Kill switch por limiter | Só lida se `configKey` não vazio | Runtime (por chamada) | Declaração/consumo: `RateLimitService#isEnabled(String)` chamado em `#tryAcquire` |
|
|
37
|
+
| `seedgrid.ratelimit.{configKey}.permits` | `Long` | inteiro `> 0` (senão `IllegalArgumentException("permits must be > 0")` na chamada) | atributo `permits` da anotação (`5`) | Não | Requisições permitidas por janela; no token bucket é a taxa de reposição por janela e a capacidade quando `burst-capacity` = 0 | Ajustar limite sem recompilar | `window`; `burst-capacity` | Runtime | `RateLimitService#resolvePermits` / `#validateConfig` |
|
|
38
|
+
| `seedgrid.ratelimit.{configKey}.window` | `java.time.Duration` | ISO-8601 (`PT30S`, `PT1M`, `PT1H`) — confirmado pelo README e teste; outros formatos (ex.: `30s`) **não confirmado**. Deve resultar em `> 0` ms | atributo `window` × `windowUnit` (`30` × `SECONDS`) | Não | Tamanho da janela (substitui `window`+`windowUnit`); também TTL das chaves no cache | Ajustar janela | `permits` | Runtime | `RateLimitService#resolveWindowMs` |
|
|
39
|
+
| `seedgrid.ratelimit.{configKey}.algorithm` | `String` → `RateLimitAlgorithm` | `fixed-window`, `sliding-window`, `token-bucket` ou os nomes do enum (`FIXED_WINDOW`, `SLIDING_WINDOW`, `TOKEN_BUCKET`) — [[SeedGrid/Extensions/resilience/Enums#RateLimitAlgorithm|RateLimitAlgorithm]]; case-insensitive, `-`→`_`. Valor inválido → `IllegalArgumentException` na chamada | atributo `algorithm` (`FIXED_WINDOW`) | Não | Seleciona estratégia `FixedWindowAlgorithm` / `SlidingWindowAlgorithm` / `TokenBucketAlgorithm` | Trocar algoritmo em produção | `burst-capacity` só afeta token bucket; `min-spacing` não afeta fixed window | Runtime | `RateLimitService#resolveAlgorithm` / `#resolveStrategy` |
|
|
40
|
+
| `seedgrid.ratelimit.{configKey}.burst-capacity` | `Long` | `>= 0` (negativo → `IllegalArgumentException`) | atributo `burstCapacity` (`0`) | Não | Capacidade do bucket; `0` = usa `permits` | Permitir rajadas | Efetivo só com `token-bucket` | Runtime | `RateLimitService#resolveBurstCapacity`; consumo em `TokenBucketAlgorithm#doAcquire` |
|
|
41
|
+
| `seedgrid.ratelimit.{configKey}.min-spacing` | `java.time.Duration` | ISO-8601 (`PT1S`, `PT0.2S`); `>= 0` | atributo `minSpacing` × `minSpacingUnit` (`0` × `MILLIS`; se `minSpacing>0` mas < 1 ms, vira 1 ms) | Não | Intervalo mínimo entre chamadas permitidas da mesma chave | Anti-martelada | **Ignorado** por `FIXED_WINDOW`; aplicado por `SLIDING_WINDOW` e `TOKEN_BUCKET` | Runtime | `RateLimitService#resolveMinSpacingMs`; consumo em `SlidingWindowAlgorithm`/`TokenBucketAlgorithm` |
|
|
42
|
+
|
|
43
|
+
Atributos **somente na anotação** (sem property): `identity`, `group`, `scope`, `emitHeaders`, `configKey`, `windowUnit`, `minSpacingUnit`. **Confirmado** (`RateLimitService` não lê outras chaves).
|
|
44
|
+
|
|
45
|
+
### 2.2 Circuit breaker — `seedgrid.circuitbreaker.{name}.*`
|
|
46
|
+
|
|
47
|
+
`{name}` = `SeedGridCircuitBreaker#name()`. Sem `name`, o circuito usa a assinatura do método como nome e **nenhuma** property é lida.
|
|
48
|
+
|
|
49
|
+
| Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Fase | Origem |
|
|
50
|
+
|---|---|---|---|---|---|---|---|---|---|
|
|
51
|
+
| `seedgrid.circuitbreaker.{name}.enabled` | `Boolean` | `true` \| `false` | `true` (fixo no código) | Não | `false`: interceptor chama o método direto, sem estado nem fallback | Kill switch por circuito | Só lida se `name` não vazio | Runtime (por chamada) | `CircuitBreakerConfigResolver#isEnabled`; consumo `CircuitBreakerInterceptor#around` |
|
|
52
|
+
| `seedgrid.circuitbreaker.{name}.sliding-window-size` | `Integer` | inteiro `> 0` (**Inferência**: 0/negativo quebraria o ring buffer; sem validação explícita) | atributo `slidingWindowSize` (`100`) | Não | Tamanho do ring buffer; em `TIME_BASED` também é a duração da janela **em segundos**. Mudar o valor descarta o estado salvo | Ajustar janela de métricas | `window-type`, `minimum-number-of-calls` | Runtime | `CircuitBreakerConfigResolver#resolve`; consumo `CacheBackedCircuitBreakerStore#addToRing/#evaluateThresholds/#deserialize` |
|
|
53
|
+
| `seedgrid.circuitbreaker.{name}.window-type` | `String` → `SlidingWindowType` | `count-based`, `time-based` (ou `COUNT_BASED`/`TIME_BASED`) — [[SeedGrid/Extensions/resilience/Enums#SlidingWindowType|SlidingWindowType]]; case-insensitive, `-`→`_` | atributo `windowType` (`COUNT_BASED`) | Não | Janela por contagem ou por tempo | Escolher semântica da janela | `sliding-window-size` | Runtime | `CircuitBreakerConfigResolver#resolve`; consumo `CacheBackedCircuitBreakerStore#evaluateThresholds` |
|
|
54
|
+
| `seedgrid.circuitbreaker.{name}.failure-rate-threshold` | `Double` | percentual (0–100; sem validação) | atributo `failureRateThreshold` (`50.0`) | Não | Abre quando `falhas*100/total >= valor` | Sensibilidade a falhas | `minimum-number-of-calls` | Runtime | `CircuitBreakerConfigResolver#resolve`; `CacheBackedCircuitBreakerStore#evaluateThresholds` |
|
|
55
|
+
| `seedgrid.circuitbreaker.{name}.slow-call-duration` | `java.time.Duration` | ISO-8601 (`PT2S`) | atributo `slowCallDurationThresholdMs` (`0` = desligado) | Não | Chamada com duração `>=` valor conta como lenta; `0` desativa a regra de lentidão | Detectar degradação | Necessária (>0) para `slow-call-rate-threshold` ter efeito | Runtime | `CircuitBreakerConfigResolver#resolve` (→ `slowCallDurationThresholdMs`); `CacheBackedCircuitBreakerStore#doRecord/#evaluateThresholds` |
|
|
56
|
+
| `seedgrid.circuitbreaker.{name}.slow-call-rate-threshold` | `Double` | percentual (0–100) | atributo `slowCallRateThreshold` (`100.0`) | Condicional (só tem efeito se `slow-call-duration` > 0) | Abre quando `lentas*100/total >= valor` | Abrir por lentidão | `slow-call-duration` | Runtime | `CircuitBreakerConfigResolver#resolve`; `CacheBackedCircuitBreakerStore#evaluateThresholds` |
|
|
57
|
+
| `seedgrid.circuitbreaker.{name}.minimum-number-of-calls` | `Integer` | inteiro `>= 0` | atributo `minimumNumberOfCalls` (`20`) | Não | Mínimo de chamadas na janela antes de avaliar thresholds | Evitar abrir com amostra pequena | Se > `sliding-window-size`, o circuito nunca abre (**Inferência**: `totalFilled` ≤ tamanho do buffer) | Runtime | `CircuitBreakerConfigResolver#resolve`; `CacheBackedCircuitBreakerStore#evaluateThresholds` |
|
|
58
|
+
| `seedgrid.circuitbreaker.{name}.open-state-duration` | `java.time.Duration` | ISO-8601 (`PT30S`) | atributo `openStateDurationMs` (`30000` ms) | Não | Tempo em `OPEN` antes de ir a `HALF_OPEN`; base do `retryAfterMs`; TTL do estado = `max(2×valor, 1h)` | Tempo de recuperação | `permitted-calls-in-half-open` | Runtime | `CircuitBreakerConfigResolver#resolve`; `CacheBackedCircuitBreakerStore#doAllowCall/#save` |
|
|
59
|
+
| `seedgrid.circuitbreaker.{name}.permitted-calls-in-half-open` | `Integer` | inteiro `> 0` | atributo `permittedCallsInHalfOpen` (`10`) | Não | Nº de sondas em `HALF_OPEN`; todas precisam ter sucesso para fechar | Recuperação gradual | `open-state-duration` | Runtime | `CircuitBreakerConfigResolver#resolve`; `CacheBackedCircuitBreakerStore#doAllowCall/#doRecord` |
|
|
60
|
+
|
|
61
|
+
Atributos **somente na anotação**: `recordExceptions` (default `{Exception.class}`), `ignoreExceptions` (default `{}`), `fallbackMethod` (default `""`), `name`. **Confirmado** (Javadoc de `CircuitBreakerConfigResolver` e código).
|
|
62
|
+
|
|
63
|
+
Total de propriedades públicas da extension: **15** (6 rate limit + 9 circuit breaker), todas com segmento dinâmico.
|
|
64
|
+
|
|
65
|
+
## 3. Propriedades de frameworks/bibliotecas
|
|
66
|
+
|
|
67
|
+
| Propriedade | Situação | Observação | Origem |
|
|
68
|
+
|---|---|---|---|
|
|
69
|
+
| `quarkus.redis.hosts` | Recomendada (quando usar `seedgrid-cache-redis`) | Conexão do Redis usado pelo provider de cache | `README.adoc` § "Configuração do Redis" |
|
|
70
|
+
| `quarkus.redis.password` 🔒 | Recomendada (se o Redis exigir) | Use `<SEGREDO:redis-password>` | `README.adoc` |
|
|
71
|
+
| `quarkus.redis.timeout` | Opcional | Exemplo no README: `PT5S` | `README.adoc` |
|
|
72
|
+
| `quarkus.redis.max-pool-size` | Opcional | Exemplo no README: `10` | `README.adoc` |
|
|
73
|
+
|
|
74
|
+
A extension não define nem exige nenhuma propriedade `quarkus.*`/`mp.*`/`smallrye.*` em código. A seleção/configuração do provider de cache (Redis/Valkey/Dragonfly) pertence à lib cache — ver [[SeedGrid/Extensions/cache/Configuracao|Configuração do cache]].
|
|
75
|
+
|
|
76
|
+
## 4. Propriedades usadas só em testes
|
|
77
|
+
|
|
78
|
+
Nenhum `application.properties` com conteúdo (o de `integration-tests/src/main/resources` está vazio). Os testes unitários mockam `Config` com estas chaves (instâncias das propriedades da seção 2):
|
|
79
|
+
|
|
80
|
+
| Chave | Teste |
|
|
81
|
+
|---|---|
|
|
82
|
+
| `seedgrid.ratelimit.checkout.permits`, `.enabled`, `.window`, `.algorithm` (`token-bucket`), `.burst-capacity` | `runtime/src/test/.../RateLimitServiceConfigOverrideTest` |
|
|
83
|
+
| `seedgrid.circuitbreaker.payments.enabled`, `.sliding-window-size`, `.window-type` (`time-based`), `.failure-rate-threshold`, `.slow-call-duration`, `.slow-call-rate-threshold`, `.minimum-number-of-calls`, `.open-state-duration`, `.permitted-calls-in-half-open` | `runtime/src/test/.../CircuitBreakerConfigResolverTest` |
|
|
84
|
+
|
|
85
|
+
Os ITs (`RedisTestBase`) montam o Redis via Testcontainers programaticamente (sem properties).
|
|
86
|
+
|
|
87
|
+
## 5. Aliases, obsoletas, renomeações
|
|
88
|
+
|
|
89
|
+
- `algorithm` e `window-type` aceitam tanto kebab-case quanto o nome do enum (normalização `trim().toUpperCase().replace('-', '_')`). **Confirmado**.
|
|
90
|
+
- `window`/`min-spacing`/`slow-call-duration`/`open-state-duration` substituem pares da anotação (`window`+`windowUnit`, `minSpacing`+`minSpacingUnit`, `slowCallDurationThresholdMs`, `openStateDurationMs`) — nomes diferentes entre anotação e property.
|
|
91
|
+
- Nenhuma propriedade obsoleta encontrada.
|
|
92
|
+
|
|
93
|
+
## 6. Configuração mínima
|
|
94
|
+
|
|
95
|
+
Nenhuma property é obrigatória: as anotações já trazem os valores. Para estado compartilhado entre instâncias, adicione um provider de cache distribuído e sua conexão:
|
|
96
|
+
|
|
97
|
+
```properties
|
|
98
|
+
# Provider seedgrid-cache-redis no classpath
|
|
99
|
+
quarkus.redis.hosts=redis://<host>:6379
|
|
100
|
+
quarkus.redis.password=<SEGREDO:redis-password>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## 7. Configuração completa comentada
|
|
104
|
+
|
|
105
|
+
```properties
|
|
106
|
+
# ===== Rate limit: um bloco por configKey usado em @SeedGridRateLimit(configKey = "...") =====
|
|
107
|
+
# liga/desliga o limiter (padrão true)
|
|
108
|
+
seedgrid.ratelimit.<configKey>.enabled=true
|
|
109
|
+
# requisições por janela (> 0)
|
|
110
|
+
seedgrid.ratelimit.<configKey>.permits=<n>
|
|
111
|
+
# janela ISO-8601 (> 0), ex.: PT1M
|
|
112
|
+
seedgrid.ratelimit.<configKey>.window=<duration>
|
|
113
|
+
# fixed-window | sliding-window | token-bucket
|
|
114
|
+
seedgrid.ratelimit.<configKey>.algorithm=<algoritmo>
|
|
115
|
+
# capacidade do bucket (>= 0; 0 = usa permits) — só token-bucket
|
|
116
|
+
seedgrid.ratelimit.<configKey>.burst-capacity=<n>
|
|
117
|
+
# intervalo mínimo entre chamadas (ISO-8601) — ignorado em fixed-window
|
|
118
|
+
seedgrid.ratelimit.<configKey>.min-spacing=<duration>
|
|
119
|
+
|
|
120
|
+
# ===== Circuit breaker: um bloco por name usado em @SeedGridCircuitBreaker(name = "...") =====
|
|
121
|
+
# liga/desliga o circuito (padrão true)
|
|
122
|
+
seedgrid.circuitbreaker.<name>.enabled=true
|
|
123
|
+
# tamanho da janela (nº de chamadas; em time-based também = segundos)
|
|
124
|
+
seedgrid.circuitbreaker.<name>.sliding-window-size=<n>
|
|
125
|
+
# count-based | time-based
|
|
126
|
+
seedgrid.circuitbreaker.<name>.window-type=<tipo>
|
|
127
|
+
# % de falhas para abrir
|
|
128
|
+
seedgrid.circuitbreaker.<name>.failure-rate-threshold=<percentual>
|
|
129
|
+
# duração a partir da qual a chamada é lenta (ISO-8601); omitir/0 desliga
|
|
130
|
+
seedgrid.circuitbreaker.<name>.slow-call-duration=<duration>
|
|
131
|
+
# % de chamadas lentas para abrir (exige slow-call-duration > 0)
|
|
132
|
+
seedgrid.circuitbreaker.<name>.slow-call-rate-threshold=<percentual>
|
|
133
|
+
# mínimo de chamadas antes de avaliar
|
|
134
|
+
seedgrid.circuitbreaker.<name>.minimum-number-of-calls=<n>
|
|
135
|
+
# tempo aberto antes do half-open (ISO-8601)
|
|
136
|
+
seedgrid.circuitbreaker.<name>.open-state-duration=<duration>
|
|
137
|
+
# sondas no half-open
|
|
138
|
+
seedgrid.circuitbreaker.<name>.permitted-calls-in-half-open=<n>
|
|
139
|
+
|
|
140
|
+
# ===== Cache distribuído (lib seedgrid-cache-redis) =====
|
|
141
|
+
quarkus.redis.hosts=redis://<host>:6379
|
|
142
|
+
quarkus.redis.password=<SEGREDO:redis-password>
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## 8. Receitas
|
|
146
|
+
|
|
147
|
+
**Desligar um limiter em produção** (método com `configKey = "forgot-password"`):
|
|
148
|
+
```properties
|
|
149
|
+
seedgrid.ratelimit.forgot-password.enabled=false
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Afrouxar o login temporariamente** (`configKey = "login"`):
|
|
153
|
+
```properties
|
|
154
|
+
seedgrid.ratelimit.login.permits=200
|
|
155
|
+
seedgrid.ratelimit.login.window=PT30S
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Trocar para token bucket com rajada e espaçamento** (`configKey = "export-create"`):
|
|
159
|
+
```properties
|
|
160
|
+
seedgrid.ratelimit.export-create.algorithm=token-bucket
|
|
161
|
+
seedgrid.ratelimit.export-create.burst-capacity=3
|
|
162
|
+
seedgrid.ratelimit.export-create.min-spacing=PT1S
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Circuito mais sensível, com detecção de lentidão** (`name = "payments"`):
|
|
166
|
+
```properties
|
|
167
|
+
seedgrid.circuitbreaker.payments.failure-rate-threshold=25
|
|
168
|
+
seedgrid.circuitbreaker.payments.minimum-number-of-calls=5
|
|
169
|
+
seedgrid.circuitbreaker.payments.slow-call-duration=PT2S
|
|
170
|
+
seedgrid.circuitbreaker.payments.slow-call-rate-threshold=80
|
|
171
|
+
seedgrid.circuitbreaker.payments.open-state-duration=PT10S
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Janela por tempo de 20 s**:
|
|
175
|
+
```properties
|
|
176
|
+
seedgrid.circuitbreaker.payments.window-type=time-based
|
|
177
|
+
seedgrid.circuitbreaker.payments.sliding-window-size=20
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## 9. Dúvidas e lacunas
|
|
181
|
+
|
|
182
|
+
- Formatos de `Duration` além de ISO-8601 (ex.: `30s`): dependem do conversor registrado no Quarkus; **não confirmado** nesta extension.
|
|
183
|
+
- Variáveis de ambiente: mapeamento descrito é **Inferência** (regra SmallRye), sem teste no repositório.
|
|
184
|
+
- Sem validação no boot: chaves com erro de digitação são silenciosamente ignoradas; valores inválidos (`algorithm`, `window-type`, `permits<=0`) só falham na chamada.
|
|
185
|
+
- `sliding-window-size` e `permitted-calls-in-half-open` não têm validação de positivo.
|
|
186
|
+
- Não há propriedade global (ex.: desligar todos os limiters ou escolher store) — apenas por `configKey`/`name`.
|