We use multiprocessing to send a newsletter via Sendinblue to our ~750k users. Sometimes a process does not complete.
observation of the problem
when I run the script several times in test mode (without sending the emails), with the same dataset.
In 80% of attempts it works correctly.
In 20% of attempts, a process never ends, which blocks the continuity of the script.
Here is the part of the script that has responsibility for the processes
def loop_on_targets(targets: list, sender_mode: dict) -> None:
"""
Loop on each customer, get email dataset and send newsletters
:param targets: list
customers
:param sender_mode:
senders object for Sendinblue, switch country
:return:
"""
if len(targets) == 0:
return
# common counter for stdout
global i
manager = Manager()
shared_list = manager.list()
# jobs limit
jobs = []
started_jobs = 0
max_jobs = 200
# START PROCESS LOOP
# for each customer get email content data from database in separated process
for process in [
Process(target=send_proxymities,
args=(BORROWER_QUERY.format(
i_owner[5],
i_owner[4],
'ROLE_OWNER',
i_owner[5],
i_owner[4]
), i_owner, 'ROLE_OWNER', shared_list)) for i_owner in
list(filter((lambda o: 'ROLE_OWNER' in o[2]), targets))] + [
Process(target=send_proxymities,
args=(OWNER_QUERY.format(
i_borrower[5],
i_borrower[4],
'ROLE_BORROWER',
i_borrower[5],
i_borrower[4]
), i_borrower, 'ROLE_BORROWER', shared_list)) for i_borrower in
list(filter((lambda b: 'ROLE_BORROWER' in b[2]), targets))
]:
# increment counter for follow-up of processed customers on stdout
i += 1
jobs.append(process)
process.start()
started_jobs += 1
# jobs limit management
if started_jobs >= max_jobs:
while started_jobs >= max_jobs:
started_jobs = 0
for job in jobs:
started_jobs += job.is_alive()
# email sending management
if len(shared_list) >= 90:
print("Send " + str(len(shared_list)))
# sending by group of 90 customers to respect the limit of the smtp service
for chunk in [shared_list[idx: idx + 90] for idx in range(0, len(shared_list), 90)]:
# send email on separated thread
threading.Thread(target=asyncio.run, args=(send_email_by_curl(list(chunk), sender_mode),)).start()
# clear shared list
shared_list[:] = []
# END PROCESS LOOP
# wait if processes are not terminated
for p in jobs:
p.join()
# email sending management
if len(shared_list) > 0:
print("Send " + str(len(shared_list)))
# sending by group of 90 customers to respect the limit of the smtp service
for chunk in [shared_list[idx: idx + 90] for idx in range(0, len(shared_list), 90)]:
# send email on separated thread
threading.Thread(target=asyncio.run, args=(send_email_by_curl(list(chunk), sender_mode),)).start()