moon icon indicating copy to clipboard operation
moon copied to clipboard

[Question] Run persistent task and run other task after

Open b2whats opened this issue 6 months ago • 4 comments

i would like to start server for test and when server started i want to run test task How can i do it in moon config ? Is it possible or I should make transit tasks for right dependency graph

b2whats avatar Jun 07 '25 15:06 b2whats

@b2whats This isn't possible because persistent tasks run forever, so it's not possible to run other tasks after them since they never complete.

The only way to achieve this is to run 2 separate moon commands, like in different terminal windows.

milesj avatar Jun 07 '25 17:06 milesj

as a solution will work:

 start-test-service:
    script: |
      echo "Starting $project server..."
      node --no-warnings build/index.js < /dev/null > /dev/null 2>&1 &
      PID=$!

      sleep 1
      
      if ! kill -0 $PID 2>/dev/null; then
        echo "❌ Server failed to start"
        exit 1
      fi

      for i in {1..5}; do
        nc -z localhost $SERVICE_PORT && break
        sleep 1
      done || {
          echo "❌ Server timeout - not responding on port $SERVICE_PORT"
          kill $PID 2>/dev/null
          exit 1
      }
      
      echo "✅ $project server started in background $SERVICE_PORT"
    deps:
      - 'build'
    env:
      NODE_CONFIG_ENV: 'autotests'
      SERVICE_PORT: '8101'
    inputs: []
    options:
      persistent: false
      cache: false

  stop-test-service:
    script: |
      echo "Stopping $project service..."
      PORT_PID=$(lsof -t -i:$SERVICE_PORT 2>/dev/null || true)
      if [ ! -z "$PORT_PID" ]; then
        kill $PORT_PID 2>/dev/null || true
        echo "✅ $project server stopped"
      fi
    env:
      SERVICE_PORT: '8101'
    options:
      cache: false

  test-api:
    command: 'vitest --run --config ./vitest.config.api.ts'
    env:
      NODE_CONFIG_ENV: 'autotests'
      SERVICE_PORT: '8101'
    options:
      outputStyle: 'stream'
      cache: false

  run-test-api:
    command: 'noop'
    deps:
      - 'start-test-service'
      - 'test-api'
      - 'stop-test-service'
    env:
      NODE_CONFIG_ENV: 'autotests'
      SERVICE_PORT: '8101'
    options:
      cache: false
      runDepsInParallel: false

but I noticed the strangeness:

if i run command (bg process) node --no-warnings build/index.js & without < /dev/null > /dev/null 2>&1 next task wouldn't runned:

  test2:
    command: 'echo 1'
    deps:
      - 'start-test-service'
    options:
      cache: false

start-test-service in this case will be endless, although if i run it directly, it will be ok

@milesj output a little inconsistent

Image

bff:start-test-service block contains bff:build info bff:test-api contains bff:start-test-service info even though the commands must be executed consistently

How i can define env for dependent tasks without copypaste ?

  • use extends, envFile (but i will have one line for every tasks) (envFile: '.env.test' or extends: XXX)
  • use env on project level (but env will be inherited by all tasks) and define in deps as
      - target: 'x'
        env:
          Y: 'autotests'
      - target: 'xx'
        env:
          Y: 'autotests'

but it will be verbose Maybe there are some other ways?

b2whats avatar Jun 08 '25 14:06 b2whats

Interesting approach.

if i run command (bg process) node --no-warnings build/index.js & without < /dev/null > /dev/null 2>&1 next task wouldn't runned:

I don't have an answer here. I'm not sure what rust does under the hood with child processes.

bff:start-test-service block contains bff:build info bff:test-api contains bff:start-test-service info even though the commands must be executed consistently

The output is correct because everything is still async and the runtime may randomly wake at certain points to progress the futures. As long as the execution of these processes is correct (it is), this is fine.

How i can define env for dependent tasks without copypaste ?

You can use yaml anchors/references.

milesj avatar Jun 08 '25 15:06 milesj

Had a similar usecase and ended up with a single bash script that takes care of everything. This works really well for my usecase:

---
id: "@unival/e2e"
stack: infrastructure
layer: automation
tags:
  - e2e
language: typescript
toolchain:
  default: node
workspace:
  inheritedTasks:
    include:
      - node/lint/check
      - node/lint/fix
      - node/format/check
      - node/format/fix
      - node/typecheck
      - node/playwright/test
tasks:
  playwright:
    script: |
      set -euo pipefail
      PORT=6006
      pnpm --filter @unival/ui ng run ui:storybook &
      STORYBOOK_PID=$!
      PGID=$(ps -o pgid= $STORYBOOK_PID | tr -d ' ')
      cleanup() {
        kill -TERM -$PGID 2>/dev/null || true
      }
      trap cleanup EXIT
      for i in {1..600}; do
        if curl -s http://localhost:$PORT/sb-healthcheck > /dev/null 2>&1; then
          break
        fi
        sleep 1
      done
      moon run @unival/e2e:node/playwright/test

I chose to run pnpm --filter... instead of moon run because I want to kill the entire process group without killing moon itself. That way the persistent server also shuts down properly after the script finishes and moon is able to complete the task as usual.

clemenscodes avatar Nov 02 '25 21:11 clemenscodes