Search code examples
resourcessimpy

Simpy resource unavialbality


I am trying to make resources unavailable for a certain time in simpy. The issue is with timeout I find the resource is still active and serving during the time it should be unavailable. Can anyone help me with this in case you have encountered such a problem. Thanks a lot!

import numpy as np
import simpy

def interarrival():
    return(np.random.exponential(10))

def servicetime():
    return(np.random.exponential(20))


def servicing(env, servers_1):
    i = 0
    while(True):
        i = i+1
        yield env.timeout(interarrival())
        print("Customer "+str(i)+ " arrived in the process at "+str(env.now))
        state = 0
        env.process(items(env, i, servers_array, state))

def items(env, customer_id, servers_array, state):
    with servers_array[state].request() as request:
        yield request
        t_arrival = env.now
        print("Customer "+str(customer_id)+ " arrived in "+str(state)+ "  at "+str(t_arrival))
        yield env.timeout(servicetime())
        t_depart = env.now
        print("Customer "+str(customer_id)+ " departed from "+str(state)+ "  at "+str(t_depart))
        if (state == 1):
            print("Customer exists")
        else:
            state = 1
            env.process(items(env, customer_id, servers_array, state))

def delay(env, servers_array):
    while(True):
        if (env.now%1440 >= 540 and env.now <= 1080):
            yield(1080 - env.now%1440)
        else:
            print(str(env.now), "resources will be blocked")
            resource_unavailability_dict = dict()
            resource_unavailability_dict[0] = []
            resource_unavailability_dict[1] = []
            for nodes in resource_unavailability_dict:
                for _ in range(servers_array[nodes].capacity):
                    resource_unavailability_dict[nodes].append(servers_array[nodes].request())
            print(resource_unavailability_dict)
            for nodes in resource_unavailability_dict:
                yield env.all_of(resource_unavailability_dict[nodes])
            if (env.now < 540):
                yield env.timeout(540)
            else:
                yield env.timeout((int(env.now/1440)+1)*1440+540 - env.now)
            for nodes in resource_unavailability_dict:
                for request in resource_unavailability_dict[nodes]:
                    servers_array[nodes].release(request)
            print(str(env.now), "resources are released")
            

env = simpy.Environment()
servers_array = []
servers_array.append(simpy.Resource(env, capacity = 5))
servers_array.append(simpy.Resource(env, capacity = 7))
env.process(servicing(env, servers_array))
env.process(delay(env,servers_array))
env.run(until=2880)

The code is given above. Actually, I have two nodes 0 and 1 where server capacities are 5 and 7 respectively. The servers are unavailable before 9AM (540 mins from midnight) and after 6 PM everyday. I am trying to create the unavailability using timeout but not working. Can you suggest how do I modify the code to incorporate it.

I am getting the error AttributeError: 'int' object has no attribute 'callbacks'which I can't figure out why ?


Solution

  • So the problem with simpy resources is the capacity is a read only attribute. To get around this you need something to seize and hold the resource off line. So in essence, I have two types of users, the ones that do "real work" and the ones that control the capacity. I am using a simple resource, which means that the queue at the schedule time will get processed before the capacity change occurs. Using a priority resource means the current users of a resource can finish their processes before the capacity change occurs , or you can use a pre-emptive resource to interrupt users with resources at the scheduled time. here is my code

    """
    one way to change a resouce capacity on a schedule
    note the the capacity of a resource is a read only atribute
    
    Programmer: Michael R. Gibbs
    """
    
    import simpy
    import random
    
    def schedRes(env, res):
        """
        Performs maintenance at time 100 and 200
    
        waits till all the resources have been seized 
        and then spend 25 time units doing maintenace 
        and then release
    
        since I am using a simple resource, maintenance
        will wait of all request that are already in 
        the queue when maintenace starts to finish
    
        you can change this behavior with a priority resource 
        or pre-emptive resource
        """
    
        # wait till first scheduled maintenance
        yield env.timeout(100)
    
        # build a list of requests for each resource
        # then wait till all requests are filled
        res_maint_list = []
        print(env.now, "Starting maintenance")
        for _ in range(res.capacity):
            res_maint_list.append(res.request())
    
        yield env.all_of(res_maint_list)
        print(env.now, "All resources seized for maintenance")
    
        # do maintenance
        yield env.timeout(25)
        print(env.now, "Maintenance fisish")
    
        # release all the resources
        for req in res_maint_list:
            res.release(req)
    
        print(env.now,"All resources released from maint")
    
        # wait till next scheduled maintenance
        dur_to_next_maint = 200 -env.now
    
        if dur_to_next_maint > 0:
            yield env.timeout(dur_to_next_maint)
    
        # do it all again
        res_maint_list = []
        print(env.now, "Starting maintenance")
        for _ in range(res.capacity):
            res_maint_list.append(res.request())
    
        yield env.all_of(res_maint_list)
        print(env.now, "All resources seized for maintenance")
    
        yield env.timeout(25)
        print(env.now, "Maintenance fisish")
    
        for req in res_maint_list:
            res.release(req)
    
        print(env.now,"All resources released from maint")
    
    
    def use(env, res, dur):
        """
        Simple process of a user seizing a resource 
        and keeping it for a little while
        """
        with res.request() as req:
            print(env.now, f"User is in queue of size {len(res.queue)}")
            yield req
            print(env.now, "User has seized a resource")
            yield env.timeout(dur)
        print(env.now, "User has released a resource")
    
    def genUsers(env,res):
        """
        generate users to seize resources
        """
        while True:
            yield env.timeout(10)
            env.process(use(env,res,21))
        
    # set up 
    env = simpy.Environment()
    res = simpy.Resource(env,capacity=2) # may want to use a priority or preemtive resource
    env.process(genUsers(env,res))
    env.process(schedRes(env, res))
    
    # start
    env.run(300)