예제 #1
0
def check_revived_treads():
    """
        Super restrictive mode. We control how many threads relive, and if we overcome a threshold, 
        daemon will be killed.
    """
    if revived_threads > MAX_REVIVED_THREADS:
        msg = "ERROR: Raise MAX_REVIVED_THREADS threads: revived_threads: %d" % revived_threads
        log.error(msg)
        g = GalotecniaSupport()
        g.process_error(msg)
        pf = file(options.pidFile, 'r')
        pid = int(pf.read().strip())
        pf.close()
        try:
            while 1:
                os.kill(pid, signal.SIGTERM)
                time.sleep(1)
        except IOError, err:
            err = str(err)
            if err.find("No such process") > 0:
                log.info("Leaving daemon...")
                os.remove(options.pidFile)
                sys.exit(0)
            else:
                log.error(str(err))
                sys.exit(1)
예제 #2
0
    def check_processing_msg_list(self):
        connectors_dict = {}
        now = datetime.datetime.now()
        top = now - datetime.timedelta(settings.DEFAULT_CHECK_DAYS)

        # Obtenemos la lista de mensajes que tienen estado temporal en el servidor
        query = SMSHistory.objects.filter(server_status__in = [NONE_STATUS, PROCESSING_STATUS], local_status = SENT_STATUS, 
                    sentDate__gte = top).order_by('sentDate')
        log.info("MessageConsulter: Consulting a list of %d messages" % len(query))
        i = 0
        for msg in query:
            status = NONE_STATUS
            try:
                # PANIC MODE!!!
                log.debug("History %d: updating status" % msg.id)
                acc_id = msg.message.account.id
                
                # Checking if message account is on memory, otherwise we add it
                if not connectors_dict.has_key(acc_id):
                    backend = msg.message.account.access.backend
                    GenericConnector = backends[backend]
                    connector = GenericConnector(msg.message.account.args())
                    connectors_dict[acc_id] = connector
                con = connectors_dict[acc_id]

                # Checking msg status, we only take first object
                [status, info] = con.get_info(msg.remote_id)[0]
                msg.server_status = status
                msg.status_info = info

                # If we got a valid status, we update send date field of msg
                if status != NONE_STATUS and status != PROCESSING_STATUS:
                    msg.sentDate = datetime.datetime.now()
                log.debug("History %s: setting server status to %s" %(msg.id, msg.server_status))
                msg.save()

            except Exception, e:
                # PANIC MODE!!!
                # If checking status proccess fails (because connector error, status
                # consult error, or while saving the msg), we continue with next task
                log.error("Error al consultar el estado del mensaje %s", msg.id)
                get_traceback(e)
                g = GalotecniaSupport()
                g.process_exception('Actualizacion del estado de mensajes', e)
    
            # Not a valid status
            if status == PROCESSING_STATUS:
                i += 1
                # Every 25 not valid consults, we wait a while
                if i % 25 == 0: 
                    time.sleep(30)
예제 #3
0
 def update_incoming_list(self):
     # PANIC MODE: This function cannot be blocked
     try:
         # Process unprocessed messages (because a daemon fail happended)
         self.process_unprocessed_msgs()
         log.debug("Checking if there are new incoming messages in %s", self.access)
         # Updating incoming message list and start to process new messages
         self.conector.decode(self.access)
     except Exception, e:
         # An unhandled exception in process message happened
         log.error("Access thread %s has failed trying to update incoming messages because %s", self.access, e)
         get_traceback(e)
         g = GalotecniaSupport()
         g.process_exception('Updating incoming messages', e)
예제 #4
0
 def process_unprocessed_msgs(self):
     """
         Processes associated messages that were not processed
         Useful in cases where, after devil fails, we want to retrieve the state in which
         stayed (in the event that access is required to process the incoming messages)
     """
     if 'process' in self.access.args():
         for no_proc_imsg in IncomingMessage.objects.filter(account__in = self.access.account_set.all(), processed = False):
             try:
                 self.conector.encode(no_proc_imsg)
             except Exception, e:
                 log.error("Error: trying to process %s message in %s access, %s", no_proc_imsg, self.access, e)
                 get_traceback(e)
                 g = GalotecniaSupport()
                 g.process_exception('Error while processing a incoming message', e)
             # If there is no fault to be processed by the system load is not generated more
             # and is marked as processed without processing date, so you can
             # retrieve the messages that failed because they have no processing time
             if not no_proc_imsg.processed:
                 no_proc_imsg.processed = True
                 no_proc_imsg.save()
예제 #5
0
    def run(self):
        """
            Send sms method. It sends SMS over a given connector (by SMS's account)
        """
        log.info("starting thread in AccountThread")
        n = 0
        while self.parent.running:
            log.info("Waiting for tasks")
            try:
                sq = self.parent.work.get(True, 10)
                n += 1
            except Queue.Empty:
                log.info("No more tasks, empty queue")
                break

            log.info("id %s: start sending %d" % (sq.get_id(), n)) 
            try:
                # KIND OF MESSAGE: SMS | MMS
                credit = SMS_CREDIT
                if sq.message.body.mms:
                    credit = MMS_CREDIT

                local_status = NONE_STATUS
                server_status = NONE_STATUS
                status_info = ''
                batch_id = ''
                today = datetime.datetime.now()
                available_credit = self.account.get_available_credit()
                if not available_credit:
                    # Run out of credit, delay sending process
                    sq.nextProcDate = today + datetime.timedelta(0,settings.DEFAULT_DEACTIVATION_TIME)
                    sq.save()
                    status_info = "Run out of credit, delayed %d day(s)" % NEXT_SEND
                    local_status = PROCESSING_STATUS
                else:
                    if sq.message.activationDate > today:
                        # This message is not active yet
                        sq.nextProcDate = sq.message.activationDate
                        sq.save()
                        status_info = "Sending delayed until activation date"
                        local_status = PROCESSING_STATUS
                    else:
                        # Active message
                        if sq.message.deactivationDate and today > sq.message.deactivationDate:
                            # Expired
                            status_info = "Sending date expired"
                            local_status = FAIL_STATUS
                        else:
                            # Not deactivation date or not sent, we create an instance
                            # of backend (connector) related to this message.
                            GenericConnector = backends[self.account.access.backend]
                            connector = GenericConnector(self.account.args())
                            log.debug("Account connector = %s (%d) is %s", self.account, self.account.id, connector)

                            # Send message
                            server_status, status_info, batch_id = self._send_message(connector, credit, sq)
                            if server_status != NONE_STATUS:
                                local_status = SENT_STATUS
                            else:
                                local_status = PROCESSING_STATUS
                                sq.nextProcDate = today + datetime.timedelta(0,settings.DEFAULT_RETRY_TIME_CONNECTOR_TEMP_FAIL)
                                log.warn("Cannot send the message over his defined connector, it will be retried in a few minutes.") 
                                sq.save()

                log.debug("Status of message %d = (local = %d, server = %d)" % (sq.message.id, local_status, server_status))
                self._update_credit(sq, local_status)
                # Status message updated
                if not sq.message.firstSentDate:
                    sq.message.firstSentDate = datetime.datetime.now()
                sq.message.lastSentDate = datetime.datetime.now()
                sq.message.save()

            except Exception, e:
                #
                # !!PANIC MODE!!
                #
                # Unhandled error. Activate a panic mode. It will mark the local error message 
                # and will be removed from the queue. For this to work the code below should return no exception. 
                # If you enter this code strange things can happen, for example, may have failed to 
                # update the credit and yet having sent the message to the operator. To try to prevent 
                # something worse going to delete the problem message. Also possible that the error is 
                # software that will be marked with all error messages.
                log.error('Fatal error in sending on AccountThread: %s' % e)
                # Forzamos el borrado del mensaje problemático
                local_status = FAIL_STATUS
                if not status_info:
                    status_info = "A falta error has happened when daemon tried to send %s over this AccountThread" % sq
                g = GalotecniaSupport()
                g.process_exception('Sending process over singularms daemon', e)
                get_traceback(e)
            
            # MessageID_smsqueueID saved before object will be deleted
            id = sq.get_id()

            # Delete smsqueue (if it doesn't have to be fowarded again)
            if local_status != PROCESSING_STATUS:
                log.info("Deleting SMSQueue object id: %d" % sq.id)
                sq.delete()
            
            # Temporal SMSHistory data
            message = sq.message
            mobile = sq.mobile
            priority = sq.priority

            # SMSHistory object creation. Write errors, sent time, sq.id and local_id about it
            sh = SMSHistory(message = message, mobile = mobile, priority = priority, 
                sentDate = datetime.datetime.now(), local_id = id, remote_id = batch_id, 
                local_status = local_status, status_info = status_info[:255], server_status = server_status)
            sh.save()

            # Task done. If this thread die before now, when parent thread calls join() method it will
            # be blocked
            self.parent.work.task_done()          

            # Main loop can continue
            log.debug("id %s: end sending" % id)