Skip to content
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

Drall stuck when running a Drush command on a remote site inside a Docker container #77

Open
beerendlauwers opened this issue May 12, 2023 · 11 comments
Labels
bug Something isn't working help wanted Extra attention is needed

Comments

@beerendlauwers
Copy link

I'm using Drall v2.1.0.

Running the command vendor/bin/drall exec drush @@site.T cr inside a container derived from php:8.1.18-cli spawns workers, but they don't return the result or exit code:

drall-hangs.mp4

My version has the code committed for #71, so I'm not sure what the issue could be.

@jigarius
Copy link
Owner

Hey! This seems to be the same as #58. I will try and take a look at this asap. Thanks.

In the meantime, can you try that command with a -y flag and see if that works?

@beerendlauwers
Copy link
Author

No difference, unfortunately. I've also tried rearranging the Drall flags, I saw that putting them after the command isn't officially supported.

drall-hangs-2.mp4

@beerendlauwers
Copy link
Author

I see the workers have been written with ConcurrentIterator\each. Could it also use parallel Workers from https://github.com/amphp/parallel ?

@beerendlauwers
Copy link
Author

Using that library didn't change things. However, I found an interesting example to pipe output: https://github.com/amphp/parallel/blob/1.x/examples/process.php

Replacing $sOutput = yield ByteStream\buffer($process->getStdout()); in BaseExecCommand with Promise\rethrow(ByteStream\pipe($process->getStdout(), ByteStream\getStdout())); (also add use Amp\Promise;) gets me output:

drall-hangs-with-output.mp4

Then entire process still hangs, unfortunately.

@beerendlauwers
Copy link
Author

I suspected that the issue was within Drush, as I've encountered a similar issue with remote commands not finishing in another situation.

We're encountering the same problem as this person: https://stackoverflow.com/questions/60694192/unittesting-a-symfony-4-2-process-runs-infinite-loop-than-times-out-wihout-un

Namely, in Symfony\Component\Process\Process::wait(), there's this code:

  $this->requireProcessIsStarted(__FUNCTION__);

  $this->updateStatus(false);

  if (null !== $callback) {
      if (!$this->processPipes->haveReadSupport()) {
          $this->stop(0);
          throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::wait".');
      }
      $this->callback = $this->buildCallback($callback);
  }

  do {
      $this->checkTimeout();
      $running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
      $this->readPipes($running, '\\' !== \DIRECTORY_SEPARATOR || !$running);
  } while ($running);

  while ($this->isRunning()) {
      $this->checkTimeout();
      usleep(1000);
  }

  if ($this->processInformation['signaled'] && $this->processInformation['termsig'] !== $this->latestSignal) {
      throw new ProcessSignaledException($this);
  }

  return $this->exitcode;

The part that is tripping us up is this:

do {
    $this->checkTimeout();
    $running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();
    $this->readPipes($running, '\\' !== \DIRECTORY_SEPARATOR || !$running);
} while ($running);
}

Printing a . in this loop produces this behaviour:

spam.mp4

After the remote command has completed, $this->processPipes->areOpen() remains true and it loops until Drush's default timeout is hit (4 hours).

The solution is simple: use $this->isRunning() instead of checking the pipes. isRunning() calls updateStatus(false), which closes the process if it's finished.

So, replacing

$running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen();

with

$running = $this->isRunning();

Gets us this:

drall-works.mp4

@beerendlauwers
Copy link
Author

beerendlauwers commented May 12, 2023

Seems like that line was introduced here: symfony/process@2ab8127?diff=split

I'm not entirely sure why this was refactored this way. Before, $this->processPipes->hasOpenHandles() was used to handle WIndows-specific code. After the refactor, it's solely used by non-Windows code...

I'll see if I can open an issue on their repository.

EDIT: There was already one present, I've mentioned my research.

@jigarius
Copy link
Owner

Thanks a tonne for the research. I'll look into this as soon as I get time. I'll have to find a project on which I can use remote aliases first.

@beerendlauwers
Copy link
Author

@jigarius It might be possible to get this fixed in Drush instead of Symfony. The maintainer seems to be fine with it if we can prove it doesn't break anything.

@jigarius
Copy link
Owner

Sounds good to me. BTW, I just pushed the first 3.x tag. If you have PHP 8.1, then I invite you to try it. There are many cool new features.

As for this issue, I'll do some research this week. For now, maybe you can SSH into the remote container and then run Drall locally.

@jigarius jigarius added bug Something isn't working help wanted Extra attention is needed labels Oct 29, 2023
@jigarius jigarius changed the title Running a Drush command on a remote site inside a Docker container seems to hang Drall stuck when running a Drush command on a remote site inside a Docker container Oct 29, 2023
@lems3
Copy link

lems3 commented Feb 13, 2024

On my side, even by getting in the container sometime it will get stuck.

The only way we found to skip that is to skip interactive questions with --no-interactive.

We use Lando for our local environment, and we don't have to SSH into our containers as long as we're patient and we use the --no-interactive flag. (patient not because of speed but because feedbacks is shown only once after each site is done).

@jigarius
Copy link
Owner

@lems3 I see. Since Drall uses a 3rd-party library for running commands in parallel, it is subject to the limitations of that library.

The output buffering was added to prevent the output of multiple Drush commands (running in parallel) from mixing with each other. There is an issue for disabling the output buffer; see #57.

As for the --no-interactive, you should be able to use -y instead. I would suggest running lando ssh before running Drall. This is because commands like lando drall drush ... can sometimes have side-effects on the command being passed into the container.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants