- Always drain response bodies you do not consume with `Cohttp_lwt.Body.drain_body body` — leaving a body unread stalls the connection and blocks all subsequent pipelined requests.
- Define server handlers as a callback passed to `Server.make ~callback ()` and start with `Server.create ~mode:(`TCP (`Port 8080))` — never call blocking I/O inside the callback without lifting it into `Lwt`.
- Implement request timeouts manually using `Lwt.pick` to race a client call against `Lwt_unix.sleep` — cohttp has no built-in timeout and will hang indefinitely on a non-responding server: `Lwt.pick [(Client.get uri >|= fun r -> `Done r); (Lwt_unix.sleep 5.0 >|= fun () -> `Timeout)]`.
- Route requests by pattern-matching on `req |> Request.uri |> Uri.path` in the main callback — keep routing as a `match` expression dispatching to named handler functions rather than nested `if/else` chains.
- Build request headers explicitly with `Header.init () |> fun h -> Header.add h "content-type" "application/json"` before `Client.post` calls — cohttp never infers content-type from the body.
- Call `Lwt_main.run` exactly once at the program entry point; every other function must return `'a Lwt.t` — mixing synchronous blocking calls (e.g. `Unix.sleep`) inside Lwt threads starves the event loop scheduler.