Skip to content

[Filesystem] Added a LockHandler #10475

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 22, 2014
Merged

[Filesystem] Added a LockHandler #10475

merged 1 commit into from
Sep 22, 2014

Conversation

lyrixx
Copy link
Member

@lyrixx lyrixx commented Mar 17, 2014

Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets #9357 , #3586
License MIT
Doc PR https://github.com/symfony/symfony-docs/pull/3956/files

Code sample:

    /**
     * {@inheritdoc}
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $lockHelper = new LockHandler('/tmp/acme/hello.lock');
        if (!$lockHelper->lock()) {
            $output->writeln('The command is already running in another process.');

            return 0;
        }

        $output->writeln(sprintf('Hello <comment>%s</comment>!', $input->getArgument('who')));

        for (;;) {
        }

        $output->writeln(sprintf('bye <comment>%s</comment>!', $input->getArgument('who')));

        $lockHelper->unlock();
    }

process-lock


$this->assertTrue($fl->isLocked('symfony-test-filesystem-lock'));
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh!

@lyrixx
Copy link
Member Author

lyrixx commented Mar 18, 2014

Actually, register_shutdown_function is resistant to fatal error. So the PID check is a bonus for linux user.

But signals don't not trigger it. Same thing for __destruct.

@cordoval
Copy link
Contributor

please add a checkbox for writing the documentation PR

{
file_put_contents($this->getLockFile($name), getmypid());
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing inheritdoc doc blocks?

@cordoval
Copy link
Contributor

should we add a soft suggest on the process component? Of course redis sounds like a good fit, about the drivers would be good to first get the use case right, so could you please provide an explanation like @webmozart does ? 👶

@lyrixx
Copy link
Member Author

lyrixx commented Mar 18, 2014

@cordoval The use case is already described in the 2 linked issues.

@malarzm
Copy link
Contributor

malarzm commented Mar 18, 2014

I think that all drivers will check for pid - isn't it better to have class AbstractLocker which could look like

abstract class AbstractLocker
{
    public function isLocked($name)
    {
        $pid=$this->retrievePid($name);
        // system based check goes here
    }

    abstract function lock($name) {  }

    abstract function unlock($name) {  }

    abstract function retrievePid($name) {  }
}

It should make all drivers more DRY :)

@lyrixx
Copy link
Member Author

lyrixx commented Mar 18, 2014

@malarzm Retrieving the PID is only possible when everything is on the same machine. So it does not make sens. More over, I think I will remove this implementation and use flock

@malarzm
Copy link
Contributor

malarzm commented Mar 18, 2014

I thought retrievePid would be less confusing than getPid ;) I meant use of $pid = file_get_contents($lockFile); for FilesystemLocker in retrievePid function

@stof
Copy link
Member

stof commented Mar 18, 2014

@malarzm what @lyrixx meant is that a locking mechanism which supports locking accross several servers (when you have 2 workers for instance) would not be based on checking a PID.

@malarzm
Copy link
Contributor

malarzm commented Mar 18, 2014

Ah right, sorry, I think I need more sleep

@cordoval
Copy link
Contributor

#3586 talks about a doctrine driver so i guess that is a request.

@lyrixx
Copy link
Member Author

lyrixx commented Mar 18, 2014

Actually, I will remove the interface. And so I will not implement doctrine or redis. Distributed lock is really too hard, with too many edge case. So We will keep something very simple, that work only for one server.

( @romainneutron found this gist for windows)


public function lock($name)
{
file_put_contents($this->getLockFile($name), getmypid());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any error handling? What about permission issues ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

already checked in the constructor.

@cordoval
Copy link
Contributor

should we add a soft suggest on the process component?

@@ -4,6 +4,7 @@ CHANGELOG
2.5.0
-----

* added a way to lock a command
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe name it a bit more generic..? It currently allows to lock anything with a given name... Mentioning command here could make users feel it only works with ConsoleCommands or things like that..

@jakzal
Copy link
Contributor

jakzal commented Mar 18, 2014

@lyrixx keep the interface maybe, to let others provide their own implementations (not in the core)?

$pid = file_get_contents($lockFile);

if (class_exists('Symfony\Component\Process\Process')) {
$process = new Process('ps -e | awk \'{print $1}\'');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could use option -p : sprintf('ps -p %d', $pid)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or kill -0 $pid and check the exitcode. This could be done with posix_kill is this function is available

@lyrixx lyrixx added the Console label Mar 26, 2014
@lyrixx lyrixx changed the title [WIP][Command] Added an helper to lock a command [Command] Added an helper to lock a command May 28, 2014
@lyrixx
Copy link
Member Author

lyrixx commented May 28, 2014

Hello. I have updated the code. All code came from @romainneutron ;)

Now, we support only one kind of driver (file-system), So there is no need for an interface. It is done on purpose. Using a lock feature in a network is a nightmare. So we do not want to support it at all.

ping @dunglas

return true;
}

flock($handle, LOCK_UN);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Success of flock is shown by return value and therefore should be checked against?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not here. See code above... Here we release the lock we get.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But the release could also fail, couldn't it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so.

@dunglas
Copy link
Member

dunglas commented May 28, 2014

I've some concerns about this implementation:

  • it doesn't fit my use case. I need blocking locks to allow a command waiting the end of a previous one before running. Here, the non blocking mode is hardcoded (and according to the PHP doc, this mode is not supported on Windows)
  • I think it's not the responsibility of this class to kill processes. Let the developer - or the OS - doing that. And what if the killed process is a daemon or something like that? Locks aren't necessary pid files.
  • The interface was a good idea IMO (and I'll probably need "network" locks soon). A memcache lock should not be too hard to implement (even outside of core as already said).

What about

interface Lock
{
    public function lock($blocking = true);
    public function unlock();
    public function isLocked();
}

@lyrixx
Copy link
Member Author

lyrixx commented May 28, 2014

it doesn't fit my use case. I need blocking locks to allow a command waiting the end of a previous one before running. Here, the non blocking mode is hardcoded (and according to the PHP doc, this mode is not supported on Windows)

Why not ;)

I think it's not the responsibility of this class to kill processes. Let the developer - or the OS - doing that. And what if the killed process is a daemon or something like that? Locks aren't necessary pid files.

We kill nothing.

The interface was a good idea IMO (and I'll probably need "network" locks soon). A memcache lock should not be too hard to implement (even outside of core as already said).

Actually, It's VERY VERY hard to implement. What if your command segfault ? nobody will release the lock... The only almost working implementation implies heart beat... And this is hard to implements. See the "warning" section I added to the LockHelper class

Then, If you need a custom lockHelper, just create a new one. There is no need to use an interface for that ;)


namespace Symfony\Component\Console\Helper;

use Symfony\Component\Console\Locker\LockerInterface;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If no interface, this statement must me removed.

@lyrixx lyrixx force-pushed the command-lock branch 2 times, most recently from 0201f9f to a7aabd2 Compare September 11, 2014 21:17
@lyrixx
Copy link
Member Author

lyrixx commented Sep 11, 2014

@Tobion Thanks for the review. I hope it's ok now ;)


$lockPath = $lockPath ?: sys_get_temp_dir();

$file = sprintf('%s/%s', $lockPath, $name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

local variable $file is not necessary. just use $this->file

@lyrixx
Copy link
Member Author

lyrixx commented Sep 22, 2014

Travis and fabbot are of. shippable no and I don't know why. ping @fabpot.

@fabpot
Copy link
Member

fabpot commented Sep 22, 2014

forget about shippable, it was just a test

@lyrixx
Copy link
Member Author

lyrixx commented Sep 22, 2014

So it's ready for merge

@fabpot
Copy link
Member

fabpot commented Sep 22, 2014

👍

@rybakit
Copy link
Contributor

rybakit commented Sep 22, 2014

Just curious what you folks think about getting rid of the file locks and using port bindings, like it's described here?

@fabpot
Copy link
Member

fabpot commented Sep 22, 2014

Thank you @lyrixx.

@fabpot fabpot merged commit 9ad8957 into symfony:master Sep 22, 2014
fabpot added a commit that referenced this pull request Sep 22, 2014
This PR was merged into the 2.6-dev branch.

Discussion
----------

[Filesystem] Added a LockHandler

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #9357 , #3586
| License       | MIT
| Doc PR        | https://github.com/symfony/symfony-docs/pull/3956/files

Code sample:

```php
    /**
     * {@inheritdoc}
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $lockHelper = new LockHandler('/tmp/acme/hello.lock');
        if (!$lockHelper->lock()) {
            $output->writeln('The command is already running in another process.');

            return 0;
        }

        $output->writeln(sprintf('Hello <comment>%s</comment>!', $input->getArgument('who')));

        for (;;) {
        }

        $output->writeln(sprintf('bye <comment>%s</comment>!', $input->getArgument('who')));

        $lockHelper->unlock();
    }
```

![process-lock](https://f.cloud.github.com/assets/408368/2443205/4f0bf3e8-ae30-11e3-9bd4-78e09e2973ad.png)

Commits
-------

9ad8957 [Filesystem] Added a lock handler
@lyrixx
Copy link
Member Author

lyrixx commented Sep 22, 2014

@rybakit your idea is interesting, but I'm not fan of it because

  • the port could be already used by another application on production server (and not on your local machine)
  • I don't know if it work well on windows
  • It takes a port.
  • It's a bit a hack, port did not designed for that, where flock are.

@iainp999
Copy link

Hi guys. I have a similar project already (https://github.com/iainp999/lockman - approach is slightly different, happy for feedback) but would be interested in contributing to a more generic solution for SF2.

@stof
Copy link
Member

stof commented Sep 26, 2014

@iainp999 We explicitly rejected adding distributed locking in core. People needing such feature would then need to use a library providing such feature (either your library, or one of the others available on Packagist)

@iainp999
Copy link

@stof oh ok, cool

weaverryan added a commit to symfony/symfony-docs that referenced this pull request Oct 18, 2014
This PR was merged into the master branch.

Discussion
----------

[Command] Added LockHelper

| Q             | A
| ------------- | ---
| Doc fix?      | no
| New docs?     | yes symfony/symfony#10475
| Applies to    | Symfony version 2.6+
| Fixed tickets | -

Commits
-------

909a294 [Filesystem] Added documentation for the new LockHandler
2bf8c55 [Filesystem] Moved current document to a dedicated folder
@GDmac GDmac mentioned this pull request Nov 10, 2014
@lyrixx lyrixx deleted the command-lock branch December 8, 2015 15:21
@temple
Copy link

temple commented Apr 3, 2017

Could you please @lyrixx provide an interface for the LockHandler class?
It would be useful to enhance this class by using wrappers.. but this means having an interface to implement.

@lyrixx
Copy link
Member Author

lyrixx commented Apr 3, 2017

@temple We do not provide an interface on purpose. It works only on one single server.

If you want something more sophisticated, please use the Lock component instead.

@temple
Copy link

temple commented Apr 3, 2017

Are you referring this one, @lyrixx ?
http://symfony.com/blog/new-in-symfony-3-3-lock-component

@lyrixx
Copy link
Member Author

lyrixx commented Apr 3, 2017

yes.

@temple
Copy link

temple commented Apr 3, 2017

Thank you very much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.