You have to keep in mind how concurrent processing of web requests works.
An attacker may sometimes send dozens or hundreds of requests in parallel. These are handled in parallel by your server, too. This means that at the start of Joomla! handling each request (that's halfway through the software stack before a response is received by the requesting client, by the way) Admin Tools sees the request is problematic. It checks if the IP is blocked by asking the database. If it's not, it sends an email (which itself takes 1-2 seconds), and writes a database record saying this IP address did a bad thing on such and such date and time.
Here are two caveats.
"Asks the database" and "writes a database record" are neither instant nor atomic operations. They take some time, typically in the area of a couple dozen milliseconds. When the server is busy, it may take even longer, even a few seconds. What is written in the database isn't immediately returned from it on a read that was already taking place but hasn't returned data yet. This means that each of those requests being handled in parallel may not be aware that the other PHP-processing processes and threads have noticed this IP is naughty already.
"Sends an email" isn't an atomic operation either. It basically means that PHP connects to the email server and tells it "please send this email". The mail server returns immediately upon placing the email in the queue. It doesn't wait for the email to be sent through the network -- which may take anywhere from milliseconds to literal days. Therefore, emails in the queue may still be delivered long after they had originally been sent from PHP code.
As everything server-related, the whole process is NOT guaranteed to be immediately consistent, rather it's guaranteed to be eventually consistent. Eventually, enough of the parallel PHP-handling processes and threads have written enough records in the database marking this IP as naughty, and enough time has passed since those writes for new PHP processes and threads to be able to read this data from the database that several of these new PHP processes and threads will block the IP. They do so, again, by sending an email, and writing a record to the database.
Once again, eventually we get consistency and any new PHP processes and threads will see the IP address is blocked and decline any further processing.
The best thing you can do is disable the email notifications for blocked requests and blocked IP addresses. This will drastically reduce the time required to reach eventual consistency.
Nicholas K. Dionysopoulos
Lead Developer and Director
🇬🇷Greek: native 🇬🇧English: excellent 🇫🇷French: basic • 🕐 My time zone is Europe / Athens
Please keep in mind my timezone and cultural differences when reading my replies. Thank you!