@logExceptions(_LOGGER)<EOL><INDENT>def jobInsertUnique(self, client, cmdLine, jobHash, clientInfo='<STR_LIT>',<EOL>clientKey='<STR_LIT>', params='<STR_LIT>', minimumWorkers=<NUM_LIT:0>,<EOL>maximumWorkers=<NUM_LIT:0>, jobType='<STR_LIT>',<EOL>priority=DEFAULT_JOB_PRIORITY):<DEDENT>
assert cmdLine, "<STR_LIT>" + repr(cmdLine)<EOL>@g_retrySQL<EOL>def insertUniqueWithRetries():<EOL><INDENT>jobHashValue = self._normalizeHash(jobHash)<EOL>jobID = None<EOL>with ConnectionFactory.get() as conn:<EOL><INDENT>row = self._getOneMatchingRowNoRetries(<EOL>self._jobs, conn, dict(client=client, job_hash=jobHashValue),<EOL>['<STR_LIT>', '<STR_LIT:status>'])<EOL>if row is not None:<EOL><INDENT>(jobID, status) = row<EOL>if status == self.STATUS_COMPLETED:<EOL><INDENT>query = '<STR_LIT>''<STR_LIT>''<STR_LIT>''<STR_LIT>''<STR_LIT>''<STR_LIT>''<STR_LIT>''<STR_LIT>''<STR_LIT>'% (self.jobsTableName,)<EOL>sqlParams = (clientInfo, clientKey, cmdLine, params,<EOL>minimumWorkers, maximumWorkers, priority,<EOL>jobType, jobID, self.STATUS_COMPLETED)<EOL>numRowsUpdated = conn.cursor.execute(query, sqlParams)<EOL>assert numRowsUpdated <= <NUM_LIT:1>, repr(numRowsUpdated)<EOL>if numRowsUpdated == <NUM_LIT:0>:<EOL><INDENT>self._logger.info(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>", jobID)<EOL><DEDENT>self._resumeJobNoRetries(conn, jobID, alreadyRunning=False)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>jobID = self._insertOrGetUniqueJobNoRetries(<EOL>conn, client=client, cmdLine=cmdLine, jobHash=jobHashValue,<EOL>clientInfo=clientInfo, clientKey=clientKey, params=params,<EOL>minimumWorkers=minimumWorkers, maximumWorkers=maximumWorkers,<EOL>jobType=jobType, priority=priority, alreadyRunning=False)<EOL><DEDENT>return jobID<EOL><DEDENT><DEDENT>try:<EOL><INDENT>jobID = insertUniqueWithRetries()<EOL><DEDENT>except:<EOL><INDENT>self._logger.exception(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>',<EOL>jobType, client, _abbreviate(clientInfo, <NUM_LIT>), clientKey, jobHash,<EOL>cmdLine)<EOL>raise<EOL><DEDENT>else:<EOL><INDENT>self._logger.info(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>',<EOL>jobID, jobType, client, _abbreviate(clientInfo, <NUM_LIT>), clientKey,<EOL>jobHash, cmdLine)<EOL><DEDENT>return jobID<EOL>
Add an entry to the jobs table for a new job request, but only if the
        same job, by the same client is not already running. If the job is already
        running, or queued up to run, this call does nothing. If the job does not
        exist in the jobs table or has completed, it will be inserted and/or started
        up again.

        This method is called by clients, like StreamMgr, that wish to only start up
        a job if it hasn't already been started up.

        Parameters:
        ----------------------------------------------------------------
        client:          Name of the client submitting the job
        cmdLine:         Command line to use to launch each worker process; must be
                          a non-empty string
        jobHash:         unique hash of this job. The client must insure that this
                          uniquely identifies this job request for the purposes
                          of detecting duplicates.
        clientInfo:      JSON encoded dict of client specific information.
        clientKey:       Foreign key.
        params:          JSON encoded dict of the parameters for the job. This
                          can be fetched out of the database by the worker processes
                          based on the jobID.
        minimumWorkers:  minimum number of workers design at a time.
        maximumWorkers:  maximum number of workers desired at a time.
        jobType:         The type of job that this is. This should be one of the
                          JOB_TYPE_XXXX enums. This is needed to allow a standard
                          way of recognizing a job's function and capabilities.
        priority:        Job scheduling priority; 0 is the default priority (
                          ClientJobsDAO.DEFAULT_JOB_PRIORITY); positive values are
                          higher priority (up to ClientJobsDAO.MAX_JOB_PRIORITY),
                          and negative values are lower priority (down to
                          ClientJobsDAO.MIN_JOB_PRIORITY). Higher-priority jobs will
                          be scheduled to run at the expense of the lower-priority
                          jobs, and higher-priority job tasks will preempt those
                          with lower priority if there is inadequate supply of
                          scheduling slots. Excess lower priority job tasks will
                          starve as long as slot demand exceeds supply. Most jobs
                          should be scheduled with DEFAULT_JOB_PRIORITY. System jobs
                          that must run at all cost, such as Multi-Model-Master,
                          should be scheduled with MAX_JOB_PRIORITY.

        retval:          jobID of the newly inserted or existing job.