LockWaitCommand.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. <?php
  2. namespace WorkflowBundle\Command;
  3. use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
  4. use Symfony\Component\Console\Input\InputInterface;
  5. use Symfony\Component\Console\Input\InputOption;
  6. use Symfony\Component\Console\Output\OutputInterface;
  7. use WorkflowBundle\Services\TaskLoggerService;
  8. class LockWaitCommand extends ContainerAwareCommand
  9. {
  10. protected function configure()
  11. {
  12. $this
  13. ->setName('lock:wait')
  14. ->setDescription('Lock wait command')
  15. ->setHelp('Lock wait command. Wait for lock a file. The lock can be either exclusive or shared')
  16. ->addArgument('filename', InputOption::VALUE_REQUIRED, 'Filename')
  17. ->addOption('command', 'c', InputOption::VALUE_REQUIRED, 'Command to execute')
  18. ->addOption('dir', null, InputOption::VALUE_REQUIRED, 'Directory path file', '/tmp')
  19. ->addOption('timeout', null, InputOption::VALUE_REQUIRED, 'Timeout execution (ms)', 600)
  20. ->addOption('no-exclusive', 'no-e', InputOption::VALUE_NONE, 'No exclusive lock')
  21. ;
  22. }
  23. /**
  24. * @param InputInterface $input
  25. * @param OutputInterface $output
  26. */
  27. protected function execute(InputInterface $input, OutputInterface $output)
  28. {
  29. $filename = $input->getArgument('filename');
  30. $command = $input->getOption('command');
  31. $dir = $input->getOption('dir');
  32. $timeout = $input->getOption('timeout');
  33. $no_exclusive = $input->getOption('no-exclusive');
  34. if ($filename && $command) {
  35. $handle = $this->fopen($filename, $dir);
  36. $this->flock($handle, $command, $timeout, $no_exclusive);
  37. } else {
  38. $output->writeln('<error>Enter a valid filename and command</error>');
  39. }
  40. }
  41. /**
  42. * @param string $filename
  43. * @param string $dir
  44. *
  45. * @return resource
  46. */
  47. protected function fopen($filename, $dir)
  48. {
  49. // limpio el filename completo
  50. $invalid_chars = array(" ", '"', "'", "&", "\\", "?", "#", "$", "//");
  51. $delimiter = DIRECTORY_SEPARATOR;
  52. $dir_pieces = explode($delimiter, str_replace($invalid_chars, '', $dir));
  53. $filename_pieces = explode($delimiter, str_replace($invalid_chars, '', $filename));
  54. $last_filename_piece = array_pop($filename_pieces);
  55. $dir = $delimiter . implode($delimiter, array_filter(array_merge($dir_pieces, $filename_pieces)));
  56. $filename = $dir . $delimiter . $last_filename_piece;
  57. if (!file_exists($dir)) {
  58. mkdir($dir, 0777, true);
  59. }
  60. return fopen($filename, "w+");
  61. }
  62. /**
  63. * @param resource $handle
  64. * @param string $command
  65. * @param int $timeout
  66. * @param boolean $no_exclusive
  67. *
  68. * @return boolean
  69. */
  70. protected function flock($handle, $command, $timeout = 600, $no_exclusive = false)
  71. {
  72. pcntl_signal(SIGALRM, function() {
  73. exit(1);
  74. });
  75. pcntl_alarm($timeout);
  76. $operation = LOCK_EX;
  77. if ($no_exclusive) {
  78. $operation = LOCK_SH;
  79. }
  80. if (flock($handle, $operation)) {
  81. $exit_code = $this->runProcess($command)['exit_code'];
  82. } else {
  83. echo 'No se pudo obtener el lock' . PHP_EOL;
  84. $exit_code = 1;
  85. }
  86. pcntl_alarm(0);
  87. pcntl_signal_dispatch();
  88. pcntl_signal(SIGALRM, SIG_DFL);
  89. flock($handle, LOCK_UN);
  90. fclose($handle);
  91. exit($exit_code);
  92. }
  93. /**
  94. * @param string $filename
  95. *
  96. * @return array
  97. */
  98. protected function runProcess($filename)
  99. {
  100. /* @var $taskloggerService TaskLoggerService */
  101. $taskloggerService = $this->getContainer()->get('flowdat_tasklogger_service');
  102. return $taskloggerService->runProcess($filename);
  103. }
  104. }