Exemplo n.º 1
0
class ResourceAgent(object):

    def __init__(self, node):
        self.node = node
        self.id = node.id
        self.trace = BaseTracer()

        # sellers are trading on multiple jobs
        self.accept_processes = {}
        self.confirm_processes = {}

        # use ring buffers for space saving since 
        # resource agents are long lived
        self.nrejected = 0
        self.cancelled = RingBuffer(400)
        self.timedout = RingBuffer(400)

    @property
    def resource(self):
        return self.node.resource

    # utility functions
    def confirm_and_start_job(self, job, other, value):
        # sending confirmation message
        confirm = Confirm(self, other, value)
        confirm.send_msg(self.node, other.node)
        
        # start procsses to listen for cancellations
        confirm_process = ConfirmProcess(self, value)
        activate(confirm_process, confirm_process.confirm())
        self.confirm_processes[job.id] = confirm_process

        # start the job
        self.resource.start(job, confirm_process)

    
    def send_reject(self, other, value):
        reject = Reject(self, other, value)
        reject.send_msg(self.node, other.node)


    # public AcceptProcess message interface
    def confirm(self, confirm):
        if confirm.id in self.accept_processes:
            process = self.accept_processes[confirm.id]
            process.signal("confirm", confirm)
        else:
            self.trace("WARNING: no accept process for confirm %s" 
                    % reject.str(self))
    
    def reject(self, reject):
        if reject.id in self.accept_processes:
            process = self.accept_processes[reject.id]
            process.signal("reject", reject)
        else:
            self.trace("WARNING: no accept process for reject %s" 
                    % reject.str(self))

 
    # public ConfirmProcess message interface
    def cancel(self, cancel):
        trace = self.trace.add("j%-5s" % cancel.id)
        self.cancelled.add(cancel.id)
        if cancel.id in self.confirm_processes:
            process = self.confirm_processes[cancel.id]
            process.signal("cancel", cancel)
        else:
            trace and trace("no confirm process for cancel, "
                    "probably out of sync")
    
    def complete(self, complete):
        trace = self.trace.add("j%-5s" % cancel.id)
        if complete.id in self.confirm_processes:
            process = self.confirm_processes[complete.id]
            process.signal("complete", complete)
        else:
            trace("WARNING: no confirm process for complete")


    #internal ConfirmProcess interface
    # this should be the same for all resource agents
    def cancel_received(self, cancel):
        trace = self.trace.add('j%-5s' % cancel.job)

        if cancel.job in self.resource.jobs:
            trace and trace("got cancel, cancelling job %s" 
                    % cancel.job.id)
            self.resource.cancel(cancel.job);
            del self.confirm_processes[cancel.job.id]
        else:
            trace("WARNING: got cancel for job not running (%s)"
                    % cancel.job.id)

    def complete_received(self, complete):
        trace = self.trace.add('j%-5s' % complete.job.id)
        trace and trace("job %s completed, cleaning up" 
                % complete.job.id)
        del self.confirm_processes[complete.job.id]
Exemplo n.º 2
0
class SBSeller(Seller):

    def __init__(self, node, rationale,  **kw):
        super(SBSeller, self).__init__(node, rationale, **kw)
        self.offers = RingBuffer(500)

    # internal ListenProcess interface
    def quote_received(self, quote):
        trace = self.trace.add('j%-5s' % quote.job.id)
        trace and trace("advert from %s at %s" % (quote.buyer, quote.buyer.node))
        
        if quote not in self.offers:
            if self.resource.can_allocate(quote.job):

                # generate a quote and send it
                self.price = self.rationale.quote()
                quote = Ask(quote.buyer, self, quote.job, self.price)
                private = PrivateQuote(quote)
                private.send_msg(self.node, quote.buyer.node)
                self.set_quote_timeout(quote, trace)

                self.offers.add(quote)
                trace and trace("sending offer %s" % quote)

            else:
                # TODO: add this record to the job object
                record.record_failure_reason(quote.job.id, "Too Busy")
                trace and trace("resource has no room for job")
                self.nrejected += 1
        else:
            trace("WARNING: received advert for job already trading for")


    def accept_received(self, quote):
        trace = self.trace.add('j%-5s' % quote.job.id)

        if quote in self.offers:
            # we know this one
            trace and trace("got accept from %s" % quote.buyer)
            
            self.cancel_quote_timeout(quote.id, trace)
            self.rationale.observe(quote, True)

            # can we still do it?
            if self.resource.can_allocate(quote.job): 
                self.confirm_and_start_job(
                        quote.job, quote.buyer, quote)
                
            else: # we cannot honour our original quote
                trace and trace("got accept, now too busy, rejecting")
                record.record_failure_reason(quote.job.id, "Too Busy Later")
                self.send_reject(quote.buyer, quote)
                self.nrejected += 1

        else: 
            trace and trace("got an accept for a job we've timed out on")


    # diable confirm/reject as in sealedbid these are buyer only
    confirm = Seller.disable("confirm")
    reject = Seller.disable("reject")

    def quote_timedout(self):
        """this is for a regular pulse timeout"""
        pass