6 — Boas práticas industriais
Prioridades, backpressure e recuperação de falhas
Até aqui, construímos um pipeline correto e funcional. Agora vem a parte que separa firmware de laboratório de firmware industrial:
👉 o que acontece quando o sistema está sob carga, quando eventos chegam mais rápido do que podem ser processados, ou quando algo falha?
Nesta seção vamos tratar de prioridades, controle de fluxo (backpressure) e estratégias de recuperação, usando mecanismos nativos do Zephyr.
6.1 Priorização correta: tempo é um recurso finito
No Zephyr, prioridade define quem vive e quem espera. Em pipelines reais:
- Nem todo evento é igualmente importante.
- Nem todo estágio tem a mesma urgência.
- Nem toda tarefa pode competir pelo mesmo executor.
Regra prática de prioridade
| Componente | Prioridade |
|---|---|
| ISR | Máxima (hardware) |
| Timer callback | Muito alta |
| Workqueue crítica | Alta |
| Processamento pesado | Média |
| Comunicação / log | Baixa |
👉 Nunca execute processamento crítico em workqueues de baixa prioridade.
6.2 Exemplo — Workqueues com prioridades distintas
#define WORKQ_FAST_PRIO 3
#define WORKQ_SLOW_PRIO 7
K_THREAD_STACK_DEFINE(fast_stack, 1024);
K_THREAD_STACK_DEFINE(slow_stack, 1024);
static struct k_work_q fast_workq;
static struct k_work_q slow_workq;
void workqueues_init(void)
{
k_work_queue_start(&fast_workq, fast_stack,
K_THREAD_STACK_SIZEOF(fast_stack),
WORKQ_FAST_PRIO, NULL);
k_work_queue_start(&slow_workq, slow_stack,
K_THREAD_STACK_SIZEOF(slow_stack),
WORKQ_SLOW_PRIO, NULL);
}
Agora:
- Aquisição e validação vão para
fast_workq - Comunicação e persistência vão para
slow_workq
Isso evita jitter e garante latência.
6.3 Backpressure: quando eventos chegam rápido demais
Em sistemas reais:
- Sensores podem oscilar.
- Comunicação pode atrasar.
- Processamento pode ficar mais lento.
Se você não controla isso, o sistema colapsa silenciosamente.
Estratégias de backpressure no Zephyr
- Semáforos limitados
- Message queues (
k_msgq) - Buffers circulares
- Descartar eventos antigos
- Coalescer eventos
6.4 Exemplo — Limitando eventos com k_msgq
#define EVENT_QUEUE_LEN 8
K_MSGQ_DEFINE(event_q, sizeof(int), EVENT_QUEUE_LEN, 4);
Produção do evento:
void produce_event(int value)
{
k_msgq_put(&event_q, &value, K_NO_WAIT);
}
Consumo:
void consumer_thread(void)
{
int value;
while (1) {
k_msgq_get(&event_q, &value, K_FOREVER);
process_value(value);
}
}
Se a fila encher:
- O produtor falha
- O sistema não explode
- Você pode decidir: descartar, logar ou sinalizar erro
6.5 Eventos colapsáveis (coalescing)
Nem todo evento precisa ser processado individualmente.
Exemplo típico:
- Leitura periódica de sensor
- Atualização de estado
- Publicação de telemetria
👉 O último valor é o que importa, não todos.
static atomic_t pending;
static void trigger_event(void)
{
if (atomic_cas(&pending, 0, 1)) {
k_work_submit(&work);
}
}
static void work_handler(struct k_work *work)
{
atomic_set(&pending, 0);
process_latest_data();
}
Isso evita:
- Tempestade de eventos
- Starvation
- Uso excessivo de memória
6.6 Recuperação de falhas no pipeline
Firmware industrial não assume sucesso.
Boas práticas:
- Timeouts explícitos
- Watchdogs lógicos
- Estados degradados
- Reset seletivo de módulos
Exemplo — Timeout lógico com timer
static void timeout_handler(struct k_timer *timer)
{
enter_safe_state();
}
K_TIMER_DEFINE(watchdog_timer, timeout_handler, NULL);
Sempre que o pipeline avança corretamente:
k_timer_start(&watchdog_timer, K_SECONDS(2), K_NO_WAIT);
Se algo travar → evento de falha.
6.7 Checklist industrial de robustez
✔ Nenhuma etapa bloqueia o pipeline inteiro
✔ Nenhuma fila cresce infinitamente
✔ Nenhuma prioridade é arbitrária
✔ Nenhum erro é silencioso
✔ Nenhuma ISR contém lógica
Esse checklist é o que diferencia IoT de brinquedo de IoT de produção.