moonrepo / moon

A build system and monorepo management tool for the web ecosystem, written in Rust.
https://moonrepo.dev/moon
MIT License
2.9k stars 157 forks source link

[bug] Double bun install #1429

Closed rhuanbarreto closed 6 months ago

rhuanbarreto commented 6 months ago

Describe the bug

My monorepo uses bun as the main platform but there's one type of task that must be run on node: Storybooks.

Node is configured to use bun as a package manager. Here's my toolchain.yml file:

bun:
  syncProjectWorkspaceDependencies: true
  version: latest
node: # Node.js is for running storybooks. They still don't support bun. https://github.com/storybookjs/storybook/issues/23279
  version: v21.7.1
  packageManager: bun
typescript:
  createMissingConfig: true
  syncProjectReferences: true
  syncProjectReferencesToPaths: true
  routeOutDirToCache: true

When I run a task in a package that depends on both bun and node, I get a double bun install that generates a race condition between them as they run at the same time. This makes the run fail.

Shouldn't moon deduplicate this package install task in this specific case?

My action graph in dot notation:

digraph {
    0 [ label="SyncWorkspace" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    1 [ label="SetupBunTool(latest)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    2 [ label="InstallBunDeps(latest)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    3 [ label="SyncBunProject(frontend-duty-handover)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    4 [ label="SetupSystemTool" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    5 [ label="SyncSystemProject(infra)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    6 [ label="SyncBunProject(library-infra)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    7 [ label="SyncBunProject(tool-cd)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    8 [ label="SyncBunProject(library-auth)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    9 [ label="SyncBunProject(library-functions)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    10 [ label="SyncBunProject(library-azure)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    11 [ label="SyncBunProject(library-ui-components)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    12 [ label="SyncBunProject(library-translations)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    13 [ label="RunTask(frontend-duty-handover:deploy)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    14 [ label="RunTask(frontend-duty-handover:build-frontend)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    15 [ label="RunTask(frontend-duty-handover:build)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    16 [ label="RunTask(frontend-duty-handover:lint)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    17 [ label="RunTask(frontend-duty-handover:format-check)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    18 [ label="RunTask(frontend-duty-handover:test)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    19 [ label="SetupNodeTool(21.7.1)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    20 [ label="InstallNodeDeps(21.7.1)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    21 [ label="RunTask(frontend-duty-handover:publish-storybook)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    22 [ label="RunTask(frontend-duty-handover:build-storybook)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    23 [ label="RunTask(infra:deploy)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    24 [ label="RunTask(infra:validate-config)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    25 [ label="RunTask(tool-cd:cli)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    26 [ label="RunTask(infra:lint)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    27 [ label="RunTask(infra:format-check)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    28 [ label="RunTask(infra:check-stack-config-schema)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    29 [ label="RunTask(tool-cd:cli)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    30 [ label="RunTask(tool-cd:azure-login)" style=filled, shape=oval, fillcolor=gray, fontcolor=black ]
    1 -> 0 [ arrowhead=box, arrowtail=box]
    2 -> 1 [ arrowhead=box, arrowtail=box]
    4 -> 0 [ arrowhead=box, arrowtail=box]
    6 -> 1 [ arrowhead=box, arrowtail=box]
    7 -> 1 [ arrowhead=box, arrowtail=box]
    5 -> 4 [ arrowhead=box, arrowtail=box]
    5 -> 6 [ arrowhead=box, arrowtail=box]
    5 -> 7 [ arrowhead=box, arrowtail=box]
    9 -> 1 [ arrowhead=box, arrowtail=box]
    10 -> 1 [ arrowhead=box, arrowtail=box]
    8 -> 1 [ arrowhead=box, arrowtail=box]
    8 -> 9 [ arrowhead=box, arrowtail=box]
    8 -> 10 [ arrowhead=box, arrowtail=box]
    12 -> 1 [ arrowhead=box, arrowtail=box]
    11 -> 1 [ arrowhead=box, arrowtail=box]
    11 -> 12 [ arrowhead=box, arrowtail=box]
    3 -> 1 [ arrowhead=box, arrowtail=box]
    3 -> 5 [ arrowhead=box, arrowtail=box]
    3 -> 8 [ arrowhead=box, arrowtail=box]
    3 -> 11 [ arrowhead=box, arrowtail=box]
    15 -> 2 [ arrowhead=box, arrowtail=box]
    15 -> 3 [ arrowhead=box, arrowtail=box]
    16 -> 2 [ arrowhead=box, arrowtail=box]
    16 -> 3 [ arrowhead=box, arrowtail=box]
    17 -> 2 [ arrowhead=box, arrowtail=box]
    17 -> 3 [ arrowhead=box, arrowtail=box]
    18 -> 2 [ arrowhead=box, arrowtail=box]
    18 -> 3 [ arrowhead=box, arrowtail=box]
    14 -> 2 [ arrowhead=box, arrowtail=box]
    14 -> 3 [ arrowhead=box, arrowtail=box]
    14 -> 15 [ arrowhead=box, arrowtail=box]
    14 -> 16 [ arrowhead=box, arrowtail=box]
    14 -> 17 [ arrowhead=box, arrowtail=box]
    14 -> 18 [ arrowhead=box, arrowtail=box]
    19 -> 0 [ arrowhead=box, arrowtail=box]
    20 -> 19 [ arrowhead=box, arrowtail=box]
    22 -> 20 [ arrowhead=box, arrowtail=box]
    22 -> 3 [ arrowhead=box, arrowtail=box]
    22 -> 16 [ arrowhead=box, arrowtail=box]
    22 -> 15 [ arrowhead=box, arrowtail=box]
    21 -> 20 [ arrowhead=box, arrowtail=box]
    21 -> 3 [ arrowhead=box, arrowtail=box]
    21 -> 22 [ arrowhead=box, arrowtail=box]
    25 -> 2 [ arrowhead=box, arrowtail=box]
    25 -> 7 [ arrowhead=box, arrowtail=box]
    24 -> 5 [ arrowhead=box, arrowtail=box]
    24 -> 25 [ arrowhead=box, arrowtail=box]
    26 -> 2 [ arrowhead=box, arrowtail=box]
    26 -> 5 [ arrowhead=box, arrowtail=box]
    27 -> 2 [ arrowhead=box, arrowtail=box]
    27 -> 5 [ arrowhead=box, arrowtail=box]
    29 -> 2 [ arrowhead=box, arrowtail=box]
    29 -> 7 [ arrowhead=box, arrowtail=box]
    28 -> 2 [ arrowhead=box, arrowtail=box]
    28 -> 5 [ arrowhead=box, arrowtail=box]
    28 -> 29 [ arrowhead=box, arrowtail=box]
    30 -> 2 [ arrowhead=box, arrowtail=box]
    30 -> 7 [ arrowhead=box, arrowtail=box]
    23 -> 5 [ arrowhead=box, arrowtail=box]
    23 -> 24 [ arrowhead=box, arrowtail=box]
    23 -> 26 [ arrowhead=box, arrowtail=box]
    23 -> 27 [ arrowhead=box, arrowtail=box]
    23 -> 28 [ arrowhead=box, arrowtail=box]
    23 -> 30 [ arrowhead=box, arrowtail=box]
    13 -> 2 [ arrowhead=box, arrowtail=box]
    13 -> 3 [ arrowhead=box, arrowtail=box]
    13 -> 14 [ arrowhead=box, arrowtail=box]
    13 -> 21 [ arrowhead=box, arrowtail=box]
    13 -> 23 [ arrowhead=box, arrowtail=box]
}
milesj commented 6 months ago

Yeah, this one seems tricky. The bun and node implementations are completely isolated from each other, so neither of them know that the other is running an install. Let me see what I can do.

rhuanbarreto commented 6 months ago

At least avoid the same type of task (sync dependencies) to run concurrently would be a solution. Not sure how to make this work though. Count on you to find a solution! 🙏

milesj commented 6 months ago

Yeah, JS having multiple runtimes really complicates things, especially when they are used together.

castarco commented 6 months ago

Yesterday I encountered a similar ¹ problem. I started a branch to add an autoInstall option (true by default, to not break current workflows) to the toolchain's bun section, to allow users to disable the automated bun install step.

This autoInstall option could be generic (not just for Bun), but I started small to see if I can get my problem solved.

I didn't finish it yet, but I hope I'll have it soon.

  1. In my case, I use NodeJS by default, and I rely on Bun to run TypeScript internal tools without having to compile them. I also rely on PNPM to manage the workspaces, which also conflicts with how Bun manages dependencies.
milesj commented 6 months ago

I have a fix landing for this in 1.24. The gist is that if both bun and node are enabled, only node will be used for installing deps. This is more of a stopgap solution for now.

But I'm open to that autoinstall setting. Was thinking of something similar.

castarco commented 6 months ago

Thank you! 😄 .

I could push what I have to a draft PR, but the reality is that, for some reason that I cannot identify yet, when I try to set that option, my compiled moon keeps complaining that the field is not in the schema.

I've spent some hours going through the code to identify what I'm missing... but so far I'm unable to find the thing that I have to change so the validator "understands" that this field is now accepted 😓 .

milesj commented 6 months ago

You may need to wipe the .moon/cache. It's probably a serde error since serde is strict about fields.

milesj commented 6 months ago

Can you try 1.24?

castarco commented 6 months ago

Can you try 1.24?

@milesj I tried, it was enough to fix my problem :) . I'm not sure about @rhuanbarreto 's case.

rhuanbarreto commented 6 months ago

Tried and it solved my case! I'm closing the issue here and will reopen if it repeats. Thanks a lot @milesj ! ❤️