Start here. This is the direct spoken answer to practice first.
Why this question matters
Retries recover transient failures only when attempts are bounded and delayed. Permanent validation errors, incompatible messages, and deterministic code failures need quarantine or dead-letter handling instead of another immediate attempt.
I would retry transient failures with bounded attempts and backoff, not an immediate tight loop. For example, a temporary HTTP 503 from a dependency can be retried after delay. A validation error or unknown message schema is probably not fixed by retrying. After max attempts or a known permanent failure, the message goes to a dead-letter or quarantine path for inspection.