Dependencies inside Resources in forked modules
Hello!
I'm starting a new project with TypeScript and currently experimenting with Comedy as a solution for scaling the application.
I ran into an issue with the way Resources are serialized and sent to the forked process which is causing a lot of headaches and seems like a big limitation (if I'm understanding this correctly).
The original Resource definition is as follows:
import { ActorSystem, ResourceDefinition } from 'comedy';
import { getResource } from '../helpers/test';
import { ComedyResource } from '../decorators/ComedyResource';
@ComedyResource('TestResource')
export default class TestResource implements ResourceDefinition<string> {
destroy(): Promise<void> | void {
// nothing to do here
return undefined;
}
getResource(): string {
// return from an imported function as a test
return getResource();
}
initialize(system: ActorSystem): Promise<void> | void {
// nothing to do here
return undefined;
}
}
But what is sent to the child process (in the create-actor message) is:
class TestResource {
destroy() {
// nothing to do here
return undefined;
}
getResource() {
// return from an imported function as a test
return test_1.getResource();
}
initialize(system) {
// nothing to do here
return undefined;
}
}; TestResource;
As you can see, the imports are all missing and there is no way this can work.
@Zephyrrus noticed that you can use require() inside the definition and to import things, but they are imported from the wrong working directory and therefore don't resolve properly.
As a workaround I considered creating dummy "shells" that would dynamically load the correct file (from disk) with require(), but that sounds very cumbersome to maintain.
Is there any solution to this? Am I missing something?
I think you need to define the resource via a path instead of passing the object itself. For my resources and actors I create them in a file like this:
import { ResourceDefinition, ActorSystem } from "comedy";
import Knex from "knex";
import fs from "fs";
export class KnexResource implements ResourceDefinition<Knex> {
// this resource is in a package called @pct-digital/knex-db-resource
static RESOURCE_PATH = "@pct-digital/knex-db-resource/dist/KnexDbResourceModule";
log: any;
knex: Knex = null as any;
async initialize(system: ActorSystem) {
this.log = system.getLog();
this.log.info("init KnexResource");
let knexConfig = (system as any).options.config.knex;
if (knexConfig == null) {
this.log.error("Cannot initialize KnexResource, the global configuration must contain a knex property!");
}
this.log.info("Initializing knex.js pool");
this.knex = Knex(knexConfig);
let result = await this.knex.raw("SELECT 1");
if (result.rowCount !== 1 || result.rows.length !== 1) {
this.log.error("knex pool test failed!");
} else {
this.log.info("knex pool setup completed!");
}
}
destroy() {
this.log.info("Destroying knex.js pool");
return this.knex.destroy();
}
getName() {
return "KnexResource";
}
getResource() {
return this.knex;
}
}
Then I add an extra file from this this actually will be loaded by comedy:
import { KnexResource } from "./KnexDbResource";
module.exports = KnexResource;
I've not found a way to use the file that contains the normal "export class KnexResource" directly, the path I use to define the resource has to point to the file that does module.exports = ...
My system is initialized like this:
const system = actors.createSystem({
config: {
knex: serverCfg.knex,
},
resources: [KnexResource.RESOURCE_PATH]
});