harlowja / fasteners

A python package that provides useful locks.
Apache License 2.0
248 stars 45 forks source link

How to handle multiple running instances? #15

Closed paulochf closed 8 years ago

paulochf commented 8 years ago

Hi!

I'm converting my code from lockfile to fasteners and then I got stuck on a problem.

I have a script started by cron about a couple minutes which I want it to be the only instance running. I think it's normal some executions last for more than 2 minutes, but I want that new instances started by cron while another is running don't wait for the lock.

Now, the script (a Django Command) is something like below:

class Command(BaseCommand):
    # ...

    @interprocess_locked("path/to/lock")
    def handle(self, *args, **options):
        # do something

but if I run it twice, one runs and the other waits.

What should I do to get the behavior I want? I guess it could be related to the context manager quoted in Readme. It's a guess, but maybe if I use it at handle() beggining instead of the decorator I could get that, but I'm finding difficult to use due the lack of documentation for the waiting rule. Something like:

class Command(BaseCommand):
    # ...

    def handle(self, *args, **options):
        ### pseudocode
        with "try to get lock at 'path/to/lock' without waiting it":
            # do something

Thank you so much!

harlowja commented 8 years ago

You probably want to use the acquire method of the lock class directly and use its non-blocking option instead of using a context manager or decorator. That'd be my recommendation since u need to handle the case of it not getting acquired and a context manager or decorator isn't really able to handle that case for u.

https://github.com/harlowja/fasteners/blob/master/fasteners/process_lock.py#L125

paulochf commented 8 years ago

Ok! Thanks for the tip!

It worked so far =D

paulochf commented 8 years ago

I wonder if it would be nice to add the blocking option to context manager and/or decorator. Maybe I could try a PR with this, but I would like to know what you think first.

harlowja commented 8 years ago

I'm unsure how it would get added to the decorator, what does it do if it is unable to get the lock, does it not call the underlying function or throw an error or something?

harlowja commented 8 years ago

I think it could be added to the context manager, but then the same question needs to be known, how does the code that is inside the context manager get to know that the lock actually wasn't acquired?

paulochf commented 8 years ago

That's why I'm asking, heh.

You're right about the decorator. I thought it could be nice but even for me it would not be so useful. I can't think any other use case right now either.

About the manager, I went to its PEP just to make sure I'm not tripping hard (my intentions were lighter, trying to be constructive :smiley:).

Here in my case, it would be enough just to log "lock could not be acquired" and then pass straight through the context code, but I guess this could be too much permissive for a locking system. :confused:

harlowja commented 8 years ago

I'm not sure u can easily pass over the context code though :-/

harlowja commented 8 years ago

Btw, u can likely (maybe) just use https://github.com/harlowja/fasteners/blob/master/fasteners/lock.py#L255 for this context manager, but u still have to handle the case where the locking didn't work out in the code that follows.

paulochf commented 8 years ago

Yeah, that's what I was looking for! I guess I missed it yesterday.

I'm OK and happy with that. :smile: Thanks for the conversation!