Improve fault tolerance by handling leadership election and other metadata changes

### Inside `client.py`

- when a `send` fails inside `broker_unaware`, reinit the connection
- when a `send` fails inside `broker_aware`, reinit the connection and reset `topics_to_brokers`
- when at least one message could not be sent, raise a `FailedPayloadsException`

### Inside `producer.py`

- when an exception occurs inside either async or sync, reload metadata

(Integration tests are in order for this PR - pending fixes for existing tests.)