Moving the geocode decision ahead of the await meant every advert that arrived while another was still geocoding read the same uncommitted row and geocoded again; six adverts for one contact made nine or more Nominatim requests instead of two, at the 1 req/s budget. track_contact_advertisement now holds a per-contact asyncio lock across the read, geocode and write, which restores the old one-at-a-time behavior for a contact while different contacts still proceed independently. The lock entry is dropped when its last holder leaves.
Also: geocoding_cache reads in the worker-thread helpers use .get() so the loop-thread expiry pass cannot raise KeyError between the check and the read, the write-block duplicate guard calls _is_duplicate_advert_packet, and the guard test loses leftover scaffolding.