breejs / bree

Bree is a Node.js and JavaScript job task scheduler with worker threads, cron, Date, and human syntax. Built for @ladjs, @forwardemail, @spamscanner, @cabinjs.
https://jobscheduler.net
MIT License
3.01k stars 78 forks source link

[question] Using Bree with NX monorepo and typescript #161

Closed ash-vd closed 2 years ago

ash-vd commented 2 years ago

I'd like to run Bree as part of a monorepo. Eventually this application should be able to be ran in a Docker container. I've setup Bree as an application (apps/application), in which I would like to load a library (libs/lib). In the root of the application (index.ts) this library is available, but it isn't found in jobs/job.ts. My guess is that it has something to do with the workers that Bree uses, but I haven't found anything related to my problem.

The error I get when I run nx serve application is:

Worker for job "job" had an error {
  err: [worker eval]:2
      console.log((0, lib_1.lib)());
                      ^

  ReferenceError: lib_1 is not defined

I've setup a demo repository, but I'll also post some relevant files here:

app/apps/project.json:

{
  "root": "apps/application",
  "sourceRoot": "apps/application/src",
  "projectType": "application",
  "targets": {
    "build": {
      "executor": "@nrwl/js:tsc",
      "outputs": ["{options.outputPath}"],
      "options": {
        "outputPath": "dist/apps/application",
        "main": "apps/application/src/index.ts",
        "tsConfig": "apps/application/tsconfig.app.json"
      },
      "dependsOn": [
        {
          "target": "build",
          "projects": "dependencies"
        }
      ]
    },
    "serve": {
      "executor": "@nrwl/js:node",
      "options": {
        "buildTarget": "application:build"
      },
      "dependsOn": [
        {
          "target": "build",
          "projects": "self"
        }
      ]
    },
    "lint": {
      "executor": "@nrwl/linter:eslint",
      "outputs": ["{options.outputFile}"],
      "options": {
        "lintFilePatterns": ["apps/application/**/*.ts"]
      }
    },
    "test": {
      "executor": "@nrwl/jest:jest",
      "outputs": ["coverage/apps/application"],
      "options": {
        "jestConfig": "apps/application/jest.config.js",
        "passWithNoTests": true
      }
    }
  },
  "tags": []
}

app/application/src/index.ts

import path from 'path';
import Bree from 'bree';

import { lib } from '@nx-bree-typescript/lib';

console.log(lib); // <--- works

const bree = new Bree({
  root: path.join(__dirname, 'jobs'),
  jobs: ['job'],
});

bree.start();

apps/application/jobs/job.ts

import { lib } from '@nx-bree-typescript/lib';

console.log(lib); // doesn't work

I also posted this question on StackOverflow.

Checklist

shadowgate15 commented 2 years ago

I'll have to take a closer look at this when I'm at my computer but I don't think that is a valid job declaration. I think that job creation should throw an error since I do not think the function it is returning could be called. Try removing the export and just calling console in the file then pass the file path in job config.

ash-vd commented 2 years ago

Thanks @shadowgate15. I've tried to change the file to your suggestion, but unfortunately that doesn't resolve my issue. I've updated the demo-repository as well.

shadowgate15 commented 2 years ago

So I have figured out the problem. It is an issue with NX. Basically NX hijacks Module._load to handle the require mappings. It does this by forking and actually running a file to grab the module that overwrites the Module._load then requiring the file that should be run. This is never passed on to the Worker since it is a new process. I will make an issue with NX and then post the link here so we can track it.

As a work around:

    {
      name: 'job',
      path: path.join(
        process.cwd(),
        'node_modules',
        '@nrwl/js/src/executors/node/node-with-require-overrides.js'
      ),
      worker: {
        env: {
          ...process.env,
          NX_FILE_TO_RUN: path.join(__dirname, 'jobs/job.js'),
        },
      },
    }

Jobs can be setup like this and they work. Basically, it recreates the code NX is doing, definitely not pretty. Hopefully, NX will come up with a solution or we can create a plugin for this, eventually.

shadowgate15 commented 2 years ago

https://github.com/nrwl/nx/issues/9047

ash-vd commented 2 years ago

Thank you very much @shadowgate15! At least I can continue now :).

shadowgate15 commented 2 years ago

For sure, this is definitely a core bug in NX since it breaks worker_threads.

ash-vd commented 2 years ago

I'm still facing some issues with this approach. If I use the js:tsc executor I'm not able to create a Docker container from the build, as there is no option to generate a package.json with this executor. When I try to switch to the node:build executor, the jobs folder isn't bundled, and bree can't find that folder.

Would it be possible to import the jobs into index.ts with the solution you proposed, as I did in my first example? That way webpack would compile the jobs-folder as well.

shadowgate15 commented 2 years ago

That fix is just for the js:node executor. You won't be able to import them into index.ts and use them the way you did because of the way worker_threads. It is a hard limitation of node.

You should be able to specify the files that are bundled in the NX configs somewhere. which should resolve the problem. There also maybe a better way to define the path for webpack. You could also copy the code from that file the path is pointed to into your code base and use that file. Also take a look at how we define the worker in ts-worker, which could make it easier for you to setup the jobs.