python 27 - Boolean check fails while multiprocessing
<p>I have a script that retrieves a list of active 'jobs' from a MySQL table and then instantiates my main script once per active job using the multiprocessing library. My multiprocessing script has a function that checks if a given job has been claimed by another thread. It does this by checking if a particular column in the DB table is/is not NULL. The DB query returns a single item tuple:</p>

<pre><code>def check_if_job_claimed():
    #...
    job_claimed = cursor.fetchone() #Returns (claim_id,) for claimed jobs, and (None,) for unclaimed jobs
    if job_claimed:
        print "This job has already been claimed by another thread."
        return
    else:
        do_stuff_to_claim_the_job
</code></pre>

<p>When I run this function <strong>without</strong> the multiprocessing portion, the claim check works just fine. But when I try to run the jobs in parallel, the claim check reads all the (None,) tuples as having value and therefore truthiness and therefore the function assumes the job has already been claimed.</p>

<p>I have tried adjusting the number of concurrent processes the multiprocessor uses, but the claim check still doesn't work... even when I set the number of processes to 1. I have also tried playing around with the if statement to see if I could make it work that way:</p>

<pre><code>if job_claimed == True
if job_claimed == (None,)
# etc. 
</code></pre>

<p>No luck though.</p>

<p>Is anybody aware of something in the multiprocessing library that would prevent my claim checking function from properly interpreting the job_claimed tuple? Maybe there's something wrong with my code?</p>

<p><strong>EDIT</strong></p>

<p>I had run some truthiness tests on the job_claimed variable in debug mode. Here are the results of those tests:</p>

<pre><code>(pdb) job_claimed
    (None,)
(pdb) len(job_claimed)
    1
(pdb) job_claimed == True
    False
(pdb) job_claimed == False
    False
(pdb) job_claimed[0]
    None
(pdb) job_claimed[0] == True
    False
(pdb) job_claimed[0] == False
    False
(pdb) any(job_claimed)
    False
(pdb) all(job_claimed)
    False
(pdb) job_claimed is not True
    True
(pdb) job_claimed is not False
    True
</code></pre>

<p><strong>EDIT</strong></p>

<p>As requested:</p>

<pre><code>with open('Resource_File.txt', 'r') as f:
    creds = eval(f.read())
connection = mysql.connector.connect(user=creds["mysql_user"],password=creds["mysql_pw"],host=creds["mysql_host"],database=creds["mysql_db"],use_pure=False,buffered=True)

def check_if_job_claimed(job_id):
    cursor = connection.cursor()
    thread_id_query = "SELECT Thread_Id FROM jobs WHERE Job_ID=\'{}\';".format(job_id) 
    cursor.execute(thread_id_query)
    job_claimed = cursor.fetchone()
    job_claimed = job_claimed[0]
    if job_claimed:
        print "This job has already been claimed by another thread. Moving on to next job..."
        cursor.close()
        return False
    else:
        thread_id = socket.gethostname()+':'+str(random.randint(0,1000))
        claim_job = "UPDATE jobs SET Thread_Id = \'{}\' WHERE Job_ID = \'{}\';".format(job_id)
        cursor.execute(claim_job)
        connection.commit()
        print "Job is now claimed"
        cursor.close()
        return True

def call_the_queen(dict_of_job_attributes):
    if check_if_job_claimed(dict_of_job_attributes['job_id']):
        instance = OM(dict_of_job_attributes) #&lt;-- Create instance of my target class
        instance.queen_bee()

#multiprocessing code
import multiprocessing as mp
if __name__ == '__main__':
    active_jobs = get_active_jobs()
    pool = mp.Pool(processes = 4)
    pool.map(call_the_queen,active_jobs)
    pool.close()
    pool.join()
</code></pre>

<p>Any non-empty tuple (or list, string, iterable, etc.) will evaluate to <code>True</code>.  It doesn't matter if the contents of the iterable are non-True.  To test that, you can use either <code>any(iterable)</code> or <code>all(iterable)</code> to test whether any or all of the items in the iterable evaluate to True.</p>

<p>However, based on your edits, your problem is likely caused by using a global connection object across multiple processes.</p>

<p>Instead, each process should create it's own connection.  </p>

<pre><code>def check_if_job_claimed(job_id):
    connection = mysql.connector.connect(user=creds["mysql_user"],password=creds["mysql_pw"],host=creds["mysql_host"],database=creds["mysql_db"],use_pure=False,buffered=True)
</code></pre>

<p>You could also try using <a href="https://dev.mysql.com/doc/connector-python/en/connector-python-connection-pooling.html" rel="nofollow">connection pooling</a>, but I'm not sure if that would work across process, and would probably require you to switch to threads instead.</p>

<p>Also, I would move all the code under <code>if __name__ == '__main__':</code> into a function.  You generally want to avoid polluting the global namespace when using multiprocessing, because when python creates a new process, it tries to copy the global state to the new process.  That can lead to some odd bugs since global variables no longer share state (since they're in separate processes), or an object either can't be serialized or loses some information during serialization when it's reconstructed in the new process.</p>

python mysql boolean multiprocessing