diff --git a/documentation/docs/.vitepress/config.ts b/documentation/docs/.vitepress/config.ts index 049a16dd..bae18801 100644 --- a/documentation/docs/.vitepress/config.ts +++ b/documentation/docs/.vitepress/config.ts @@ -70,7 +70,7 @@ export default defineConfig({ { text: 'Logging', link: '/monitor/logging' }, { text: 'Health', link: '/monitor/health' }, { text: 'Procedures', link: '/monitor/procedures' }, - { text: 'Nodes', link: '/monitor/nodes' } + { text: 'Workers', link: '/monitor/workers' } ] }, { diff --git a/documentation/docs/deploy/environments.md b/documentation/docs/deploy/environments.md index 2c6f8656..4631c294 100644 --- a/documentation/docs/deploy/environments.md +++ b/documentation/docs/deploy/environments.md @@ -48,9 +48,9 @@ If you wonder why we've used 'standalone' instead of 'development' for the namin Distributed applications require more of the infrastructure that comes with a cost. Therefore we like to keep things simple and try to use the standalone setup in production as long as possible. We recommend only using multiple Jitar services for availability and scalability reasons. -Setting up a distributed environment requires the same steps as a standalone setup. The only difference is that you need to create a configuration per service like the repository, gateway, and node(s). For the naming we use the service type, like we do with the standalone. Don't forget to add scripts to the `package.json` file. +Setting up a distributed environment requires the same steps as a standalone setup. The only difference is that you need to create a configuration per service like the repository, gateway, and worker(s). For the naming we use the service type, like we do with the standalone. Don't forget to add scripts to the `package.json` file. -If your environment requires multiple nodes, you can append a node name to the configuration. For example "node-sales", "node-orders", etc.. +If your environment requires multiple workers, you can append a name to the configuration. For example "worker-sales", "worker-orders", etc.. ## Other environments diff --git a/documentation/docs/deploy/health-checks.md b/documentation/docs/deploy/health-checks.md index 6211faaa..1ccce08c 100644 --- a/documentation/docs/deploy/health-checks.md +++ b/documentation/docs/deploy/health-checks.md @@ -13,7 +13,7 @@ next: # Health checks -The [gateway service](../fundamentals/runtime-services#gateway) determines if a node still can be used safely by frequently checking its health. Health checks are used for health determination. Jitar has no out-of-the-box health checks, but you can create and add your own. A common use case is for checking database availability. In case a node can't access its database, we want the gateway to stop using it. Health checks can be added to any of the services. +The [gateway service](../fundamentals/runtime-services#gateway) determines if a worker still can be used safely by frequently checking its health. Health checks are used for health determination. Jitar has no out-of-the-box health checks, but you can create and add your own. A common use case is for checking database availability. In case a worker can't access its database, we want the gateway to stop using it. Health checks can be added to any of the services. ::: warning BREAKING CHANGES Version 0.5 introduced breaking changes. Please check our [migration guide](https://github.com/MaskingTechnology/jitar/blob/main/migrations/migrate-from-0.4.x-to-0.5.0.md) for more information. @@ -58,17 +58,17 @@ export default instance; We can use this module file for the registration at the service: ```json -// services/node.json +// services/worker.json { "url": "http://localhost:3000", "healthChecks": ["./databaseHealthCheck"], - "node": + "worker": { // ... } } ``` -Once added, the node will trigger the check automatically. You can also check yourself using the health API. More information on this can be found in the [MONITOR section](../monitor/health). +Once added, the worker will trigger the check automatically. You can also check yourself using the health API. More information on this can be found in the [MONITOR section](../monitor/health). **Note** that health checks are defined at the root level of the configuration. This means you can add health checks for all service types. When using external monitoring tools that monitor a cluster, this could be useful. diff --git a/documentation/docs/deploy/load-balancing.md b/documentation/docs/deploy/load-balancing.md index 4997dbea..461eaa0a 100644 --- a/documentation/docs/deploy/load-balancing.md +++ b/documentation/docs/deploy/load-balancing.md @@ -15,7 +15,7 @@ next: Jitar has out-of-the-box load balancing support. It's provided by the [gateway service](../fundamentals/runtime-services#gateway), so that needs to be added to your environment in order to use it. -The load balancing system operates on function level. If a function is available on multiple nodes, the gateway will automatically balance the requests round robin over the nodes. The [function's fully qualified name (FQN)](../fundamentals/building-blocks#fully-qualified-name-fqn) is used to uniquely identify the functions. +The load balancing system operates on function level. If a function is available on multiple workers, the gateway will automatically balance the requests round robin over the workers. The [function's fully qualified name (FQN)](../fundamentals/building-blocks#fully-qualified-name-fqn) is used to uniquely identify the functions. -When a node registers itself at the gateway, the node will provide the FQNs of the functions it contains. The gateway creates a balancer per FQN and uses the next node per request. When a node contains FQNs that are already registered by the gateway, it will add the node to the balancer. +When a worker registers itself at the gateway, the worker will provide the FQNs of the functions it contains. The gateway creates a balancer per FQN and uses the next worker per request. When a worker contains FQNs that are already registered by the gateway, it will add the worker to the balancer. diff --git a/documentation/docs/deploy/segmentation.md b/documentation/docs/deploy/segmentation.md index d7553ee7..c1a25b53 100644 --- a/documentation/docs/deploy/segmentation.md +++ b/documentation/docs/deploy/segmentation.md @@ -82,12 +82,12 @@ Imports have multiple properties that can be configured. These properties will b ### Trusted clients -When building a distributed application, you don't want all functions to be available by the outside world. Some functions are only used internally by other segments. To protect the access to these functions, Jitar provides a `trustKey` property in the [runtime services](../fundamentals/runtime-services#node). This key is used to create trusted clients. Trusted clients can access functions with the `protected` access level. +When building a distributed application, you don't want all functions to be available by the outside world. Some functions are only used internally by other segments. To protect the access to these functions, Jitar provides a `trustKey` property in the [runtime services](../fundamentals/runtime-services#worker). This key is used to create trusted clients. Trusted clients can access functions with the `protected` access level. -Any client that wants to access a protected function must provide a valid key. It needs to be added to the http header `X-Jitar-Trust-Key`. Any node that has a valid key is automatically considered a trusted client, and adds the access key to the http header of outgoing requests. Any node that doesn't have a valid access key is considered an untrusted client and can only access `public` functions. +Any client that wants to access a protected function must provide a valid key. It needs to be added to the http header `X-Jitar-Trust-Key`. Any worker that has a valid key is automatically considered a trusted client, and adds the access key to the http header of outgoing requests. Any worker that doesn't have a valid access key is considered an untrusted client and can only access `public` functions. ::: info Note -To enable trusted clients, the gateway must always have a trusted key configured. Any node that wants to register itself as a trusted client, must have the same value for the `trustKey` in its configuration. +To enable trusted clients, the gateway must always have a trusted key configured. Any worker that wants to register itself as a trusted client, must have the same value for the `trustKey` in its configuration. ::: ### Access protection diff --git a/documentation/docs/develop/application-structure.md b/documentation/docs/develop/application-structure.md index 0625e2ff..3b79d558 100644 --- a/documentation/docs/develop/application-structure.md +++ b/documentation/docs/develop/application-structure.md @@ -130,8 +130,8 @@ The `services` folder contains all [service configuration](../fundamentals/runti ```txt services ├─ gateway.json -├─ node-account.json -├─ node-reporting.json +├─ worker-account.json +├─ worker-reporting.json ├─ proxy.json ├─ repository.json └─ standalone.json diff --git a/documentation/docs/develop/error-handling.md b/documentation/docs/develop/error-handling.md index 45bdf099..5da08c41 100644 --- a/documentation/docs/develop/error-handling.md +++ b/documentation/docs/develop/error-handling.md @@ -13,7 +13,7 @@ next: # Error handling -For handling errors the default JavaScript error system can be used for throwing and catching errors. When an error occurs it will be passed to the calling procedure until it’s catched like any normal JavaScript application. If the error occurs on a remote server, the error will be (de)serialized and rethrown on the calling node. +For handling errors the default JavaScript error system can be used for throwing and catching errors. When an error occurs it will be passed to the calling procedure until it’s caught like any normal JavaScript application. If the error occurs on a remote server, the error will be (de)serialized and thrown on the calling worker. You can create your own custom errors and use the `instanceof` operator to distinguish them like this: diff --git a/documentation/docs/develop/middleware.md b/documentation/docs/develop/middleware.md index f212e0c9..d997a9af 100644 --- a/documentation/docs/develop/middleware.md +++ b/documentation/docs/develop/middleware.md @@ -94,19 +94,19 @@ export default instance; We can use this module file for the registration at the service: ```json -// services/node.json +// services/worker.json { "url": "http://localhost:3000", - "node": + "worker": { "middlewares": ["./defaultRequestLogger"] } } ``` -**Note** that middleware can only be added to a node, gateway, proxy and standalone service because they are actively involved with the communication system. +**Note** that middleware can only be added to a worker, gateway, proxy and standalone service because they are actively involved with the communication system. -It's likely that different services require different middleware. For example, you might want to add authentication middleware to the gateway and authorization middleware to the node. +It's likely that different services require different middleware. For example, you might want to add authentication middleware to the gateway and authorization middleware to the worker. ::: warning KEEP IN MIND Middleware is executed in the order of registration. This means that the middleware that is added first is called first. diff --git a/documentation/docs/develop/security.md b/documentation/docs/develop/security.md index 03d9d987..1912d249 100644 --- a/documentation/docs/develop/security.md +++ b/documentation/docs/develop/security.md @@ -33,7 +33,7 @@ The first endpoint is for requesting [assets](./assets). By default all files ar Assets can be whitelisted per file, or by using glob patterns. For example the pattern `assets/**/*` whitelists all files and subfolder files in the assets folder. -The second endpoint is for requesting module files internally used by nodes to load their functions. Requesting a module file requires a valid client id provided by the repository at the registration of a node. The repository only allows requesting files with the .js extension that are placed in the application folder. To prevent any form of information leakage make sure the code does not contain sensitive information (like access keys). +The second endpoint is for requesting module files internally used by workers to load their functions. Requesting a module file requires a valid client id provided by the repository at the registration of a worker. The repository only allows requesting files with the .js extension that are placed in the application folder. To prevent any form of information leakage make sure the code does not contain sensitive information (like access keys). ::: tip PRO TIP To prevent the access of server modules from any client, make sure that all modules are registered in a server [segment](../fundamentals/building-blocks#segments). The repository will provide a remote implementation if a client tries to load the module. Remote implementations do not contain any information other than function and parameter names. @@ -57,7 +57,7 @@ export default class Authentication implements Middleware } ``` -In a distributed setup we register this middleware at the [gateway service](../fundamentals/runtime-services.md#gateway) to make sure a node only gets called when the user is authenticated. The authorization may depend on attributes gathered during the execution of the function. Therefore we add the authorization middleware to the [node service](../fundamentals/runtime-services#node). +In a distributed setup we register this middleware at the [gateway service](../fundamentals/runtime-services.md#gateway) to make sure a worker only gets called when the user is authenticated. The authorization may depend on attributes gathered during the execution of the function. Therefore we add the authorization middleware to the [worker service](../fundamentals/runtime-services#worker). ```ts import { Middleware, Request, Response, NextHandler } from 'jitar'; diff --git a/documentation/docs/examples/concepts.md b/documentation/docs/examples/concepts.md index 3518d365..05fa4c10 100644 --- a/documentation/docs/examples/concepts.md +++ b/documentation/docs/examples/concepts.md @@ -28,7 +28,7 @@ This example demonstrates how to distribute an application in production. It als ## Load balancing -Jitar comes with load balancing capabilities out-of-the-box. This example demonstrates how to load balance application segments by running them on multiple nodes. +Jitar comes with load balancing capabilities out-of-the-box. This example demonstrates how to load balance application segments by running them on multiple workers. [View in repository](https://github.com/MaskingTechnology/jitar/tree/main/examples/concepts/load-balancing){target="_blank"} @@ -64,7 +64,7 @@ This example demonstrates how to set up a node client. It’s for you when you a ## Health checks -For the health of a cluster it’s important that nodes can communicate their health status. In this example you’ll learn how to create heath checks and request the health of a service. +For the health of a cluster it’s important that workers can communicate their health status. In this example you’ll learn how to create heath checks and request the health of a service. [View in repository](https://github.com/MaskingTechnology/jitar/tree/main/examples/concepts/health-checks){target="_blank"} diff --git a/documentation/docs/fundamentals/runtime-services.md b/documentation/docs/fundamentals/runtime-services.md index f9f3366b..9da3e707 100644 --- a/documentation/docs/fundamentals/runtime-services.md +++ b/documentation/docs/fundamentals/runtime-services.md @@ -100,21 +100,21 @@ A full configuration example looks like this. This is a core service that is always required, except when running Jitar as a [standalone service](#standalone). -## Node +## Worker -A node loads application segments and runs its functions on request. +A worker loads application segments and runs its functions on request. ### Segmentation -A node can load one or multiple segments, making it very easy to combine application pieces that have to be scaled yet. This strategy can save you a lot on hosting costs! +A worker can load one or multiple segments, making it very easy to combine application pieces that have to be scaled yet. This strategy can save you a lot on hosting costs! ::: warning KEEP IN MIND -Like any other service, a node runs on the server. Keep this in mind when creating and selecting the segments. +Like any other service, a worker runs on the server. Keep this in mind when creating and selecting the segments. ::: ### Gateway registration -When configured, a node can register itself to a [gateway service](#gateway) to become available in the cluster. +When configured, a worker can register itself to a [gateway service](#gateway) to become available in the cluster. ### Configuration properties @@ -130,8 +130,8 @@ A full configuration example looks like this: ```json { - "url": "http://node.example.com:3000", - "node": + "url": "http://worker.example.com:3000", + "worker": { "gateway": "http://gateway.example.com:3000", "repository": "http://repository.example.com:3000", @@ -148,19 +148,19 @@ This is a core service that is always required, except when running Jitar as a [ ## Gateway -The gateway provides a single point of access for running remote application functions. It acts as a mediator between a client and multiple node services. +The gateway provides a single point of access for running remote application functions. It acts as a mediator between a client and multiple worker services. ### Routing -When a function request comes in, the gateway will look for a node containing the function and forwards the request. +When a function request comes in, the gateway will look for a worker containing the function and forwards the request. ### Load balancing -If a function is available on multiple nodes, the gateway will automatically balance the requests round robin over the nodes. +If a function is available on multiple workers, the gateway will automatically balance the requests round robin over the workers. -### Node monitoring +### Worker monitoring -The availability of nodes is actively monitored. If a node cannot be reached or replies to have [an unhealthy state](../monitor/health.md), it will be removed from the gateway. +The availability of workers is actively monitored. If a worker cannot be reached or replies to have [an unhealthy state](../monitor/health.md), it will be removed from the gateway. ### Caching @@ -171,7 +171,7 @@ There aren't any caching options yet, but we are planning on implementing them. The following configuration properties are available: * repository - url of the repository (required). -* monitor - node monitoring interval in milliseconds (optional, default `5000`). +* monitor - worker monitoring interval in milliseconds (optional, default `5000`). * middlewares - list of [middleware modules](../develop/middleware.md) to load (optional). * trustKey - key for creating trusted clients (optional). @@ -192,22 +192,22 @@ A full configuration example looks like this: ### When to use -This service is used for creating a cluster and is only useful when working with multiple nodes. It also works with a single node, but adds a lot of overhead. +This service is used for creating a cluster and is only useful when working with multiple workers. It also works with a single worker, but adds a lot of overhead. ## Proxy -The proxy acts as an intermediary between clients and a Jitar cluster. It's a single point of access for both the [repository](#repository) and [gateway](#gateway) / [node](#node) services. +The proxy acts as an intermediary between clients and a Jitar cluster. It's a single point of access for both the [repository](#repository) and [gateway](#gateway) / [worker](#worker) services. ### Request forwarding -The single purpose of the proxy is to forward requests to the right service. RPC requests are forwarded to the [gateway](#gateway) or [node](#node) service (depending on the configuration). Other requests are forwarded to the repository. +The single purpose of the proxy is to forward requests to the right service. RPC requests are forwarded to the [gateway](#gateway) or [worker](#worker) service (depending on the configuration). Other requests are forwarded to the repository. ### Configuration properties The following configuration properties are available: -* gateway - url of the gateway (optional if node property set). -* node - url of the node (optional if gateway property set). +* gateway - url of the gateway (optional if worker property set). +* worker - url of the worker (optional if gateway property set). * repository - url of the repository (required). * middlewares - list of [middleware modules](../develop/middleware.md) to load (optional). @@ -234,7 +234,7 @@ This service is not required, but very helpful for protecting your cluster. Comm ## Standalone -Combines the repository and node core services into a single instance. +Combines the repository and worker core services into a single instance. ### Configuration properties diff --git a/documentation/docs/guides/creating-a-cluster.md b/documentation/docs/guides/creating-a-cluster.md index 34e2c5b0..89352813 100644 --- a/documentation/docs/guides/creating-a-cluster.md +++ b/documentation/docs/guides/creating-a-cluster.md @@ -2,8 +2,8 @@ layout: doc prev: - text: Node monitoring - link: /monitor/nodes + text: Worker monitoring + link: /monitor/workers next: text: Add Jitar to an existing project @@ -33,24 +33,24 @@ In-depth information on creating segments can be found in the [segmentation sect ### Step 3: Configure the cluster -Once the segmentation strategy is defined, the cluster needs to be configured. A cluster always requires the [repository](../fundamentals/runtime-services#repository), [gateway](../fundamentals/runtime-services#gateway) and [node](../fundamentals/runtime-services#node) services, so you need to configure them separately. A separate node configuration is required for each (backend) segment. +Once the segmentation strategy is defined, the cluster needs to be configured. A cluster always requires the [repository](../fundamentals/runtime-services#repository), [gateway](../fundamentals/runtime-services#gateway) and [worker](../fundamentals/runtime-services#worker) services, so you need to configure them separately. A separate worker configuration is required for each (backend) segment. In-depth information on configuring the services can be found in the [runtime services section](../fundamentals/runtime-services). ### Step 4: Deploy the cluster -The final step is to deploy the cluster. You can spin up as many nodes per segment as you want, Jitar will [automatically balance the load](../deploy/load-balancing) between them. Keep in mind that using multiple services always leads to performance loss due to network latency. Therefore it's important to perform some tests before going into production. In some cases some tweaking of the segmentation strategy or the number of nodes is required to get it right. You can only find out by measuring it. +The final step is to deploy the cluster. You can spin up as many workers per segment as you want, Jitar will [automatically balance the load](../deploy/load-balancing) between them. Keep in mind that using multiple services always leads to performance loss due to network latency. Therefore it's important to perform some tests before going into production. In some cases some tweaking of the segmentation strategy or the number of workers is required to get it right. You can only find out by measuring it. ## Reliability Some parts of an application are more important than others. Parts that are crucial might need a guarantee of their availability. In this case it's a good idea to set up a cluster. -The [gateway service](../fundamentals/runtime-services#gateway) provides a failover system out-of-the box that uses the [health system](../monitor/health) for monitoring the availability of its nodes. If a node doesn't respond or returns an unhealthy state, the gateway will stop using the node and resort to the remaining nodes. This means that a cluster with multiple nodes is required to be able to guarantee availability. +The [gateway service](../fundamentals/runtime-services#gateway) provides a failover system out-of-the box that uses the [health system](../monitor/health) for monitoring the availability of its workers. If a worker doesn't respond or returns an unhealthy state, the gateway will stop using the worker and resort to the remaining workers. This means that a cluster with multiple workers is required to be able to guarantee availability. -Setting up an availability cluster requires the same steps as [setting up a scalability cluster](#scalability), but with different reasoning. We do not recommend changing the segmentation strategy for adding reliability. Instead you can simply spin up multiple instances of the existing node(s). +Setting up an availability cluster requires the same steps as [setting up a scalability cluster](#scalability), but with different reasoning. We do not recommend changing the segmentation strategy for adding reliability. Instead you can simply spin up multiple instances of the existing worker(s). ## Security Limiting and protecting access to public services is always recommended. For the protection of a public [standalone service](../fundamentals/runtime-services#standalone) or a cluster of services, the proxy service could be placed in a [DMZ](https://en.wikipedia.org/wiki/DMZ_(computing)){target="_blank"}. -The proxy only forwards requests to other services. The RPC calls are forwarded to a [gateway](../fundamentals/runtime-services#gateway) or [node](../fundamentals/runtime-services#node) and the rest of the calls are forwarded to the [repository](../fundamentals/runtime-services#repository). When the application is deployed as a [standalone service](../fundamentals/runtime-services#standalone), both services run on the same server. +The proxy only forwards requests to other services. The RPC calls are forwarded to a [gateway](../fundamentals/runtime-services#gateway) or [worker](../fundamentals/runtime-services#worker) and the rest of the calls are forwarded to the [repository](../fundamentals/runtime-services#repository). When the application is deployed as a [standalone service](../fundamentals/runtime-services#standalone), both services run on the same server. diff --git a/documentation/docs/internals/caching.md b/documentation/docs/internals/caching.md index 3eebe430..4cac81a8 100644 --- a/documentation/docs/internals/caching.md +++ b/documentation/docs/internals/caching.md @@ -29,10 +29,10 @@ export const files = [ ]; ``` -The second contains the actual segment model that holds a full description for all its functions (called procedures in this context). It's used by the node service to load their segments. +The second contains the actual segment model that holds a full description for all its functions (called procedures in this context). It's used by the worker service to load their segments. ```js -// {segment name}.segment.node.js +// {segment name}.segment.worker.js const { default : $1 } = await __import("./file1.js", "application", false); const { a : $2, b : $3 } = await __import("./file2.js", "application", false); const { Segment, /* more */} = await __import("jitar", "runtime", false); diff --git a/documentation/docs/internals/data-serialization.md b/documentation/docs/internals/data-serialization.md index a26168f1..6d9b499f 100644 --- a/documentation/docs/internals/data-serialization.md +++ b/documentation/docs/internals/data-serialization.md @@ -13,7 +13,7 @@ next: # Data serialization -Jitar comes with a powerful (de)serializer that is used for sharing data between nodes. In this section you'll find more information on this topic.. +Jitar comes with a powerful (de)serializer that is used for sharing data between workers. In this section you'll find more information on this topic.. Note: The serializer is available as a separate NPM package that you can use in your own project. You can find more information on this in the [readme of the package](https://github.com/MaskingTechnology/jitar/blob/main/packages/serialization/README.md){target="_blank"}. diff --git a/documentation/docs/monitor/health.md b/documentation/docs/monitor/health.md index 070379d6..862616a5 100644 --- a/documentation/docs/monitor/health.md +++ b/documentation/docs/monitor/health.md @@ -13,7 +13,7 @@ next: # Health -Jitar provides a health API to check the health of any service. This API is internally used by the gateway to check the health of its nodes, but can also be used for external monitoring. This API triggers all [health checks](../deploy/health-checks) added to the service. +Jitar provides a health API to check the health of any service. This API is internally used by the gateway to check the health of its workers, but can also be used for external monitoring. This API triggers all [health checks](../deploy/health-checks) added to the service. There are two types of health checks available. Both are explained next. @@ -22,7 +22,7 @@ There are two types of health checks available. Both are explained next. If you're only interested in the overall health of a service, you can use the following endpoint. ```http -GET http://node.example.com:3000/health/status HTTP/1.1 +GET http://worker.example.com:3000/health/status HTTP/1.1 ``` This will return a boolean value indicating its health. When `true` the service is healthy, when `false` it's unhealthy. @@ -32,7 +32,7 @@ This will return a boolean value indicating its health. When `true` the service If you want to get more detailed health information, for example when the overall status returns false, you can use the following endpoint. ```http -GET http://node.example.com:3000/health HTTP/1.1 +GET http://worker.example.com:3000/health HTTP/1.1 ``` This will return a JSON object with the health details of each health check in the following format. diff --git a/documentation/docs/monitor/logging.md b/documentation/docs/monitor/logging.md index b0e6f320..50957770 100644 --- a/documentation/docs/monitor/logging.md +++ b/documentation/docs/monitor/logging.md @@ -30,7 +30,7 @@ The debug level is the most verbose level. It will output all debug, info, warn * Health requested * Health status requested -It's advisable to not use the debug level in production because the health of a node gets requested frequently. If you experience any issues with this, you can use this mode. +It's advisable to not use the debug level in production because the health of a worker gets requested frequently. If you experience any issues with this, you can use this mode. ## Info @@ -40,7 +40,7 @@ The info level will output all info, warn and error messages. The info level con * Assets retrieved * Client registration * Module retrieval -* Node registration / retrieval +* Worker registration / retrieval * Registered procedure names * Forward message * RPC registration / execution @@ -61,5 +61,5 @@ The error level is the most severe level. This level contains messages of all ru * Asset that could not be loaded * Module that could not get loaded -* Node that could not get added +* Worker that could not get added * Procedure that threw an error diff --git a/documentation/docs/monitor/procedures.md b/documentation/docs/monitor/procedures.md index 32f22e3d..84cb1ab5 100644 --- a/documentation/docs/monitor/procedures.md +++ b/documentation/docs/monitor/procedures.md @@ -6,14 +6,14 @@ prev: link: /monitor/health next: - text: Nodes - link: /monitor/nodes + text: Workers + link: /monitor/workers --- # Procedures -Both the [gateway service](../fundamentals/runtime-services#gateway) and the [node service](../fundamentals/runtime-services#node) keep a list of functions ([FQNs](../fundamentals/building-blocks#fully-qualified-name-fqn)) that can be run as remote procedures using the [RPC API](../integrate/rpc-api). This list can be requested with the procedures API. +Both the [gateway service](../fundamentals/runtime-services#gateway) and the [worker service](../fundamentals/runtime-services#worker) keep a list of functions ([FQNs](../fundamentals/building-blocks#fully-qualified-name-fqn)) that can be run as remote procedures using the [RPC API](../integrate/rpc-api). This list can be requested with the procedures API. ```http GET http://proxy.example.com:3000/procedures HTTP/1.1 @@ -28,4 +28,4 @@ The API returns a list of procedure names (FQNs) that are registered with this s ] ``` -This API is also available for the [proxy service](../fundamentals/runtime-services#proxy). It will forward the request to its configured gateway / node. +This API is also available for the [proxy service](../fundamentals/runtime-services#proxy). It will forward the request to its configured gateway / worker. diff --git a/documentation/docs/monitor/nodes.md b/documentation/docs/monitor/workers.md similarity index 54% rename from documentation/docs/monitor/nodes.md rename to documentation/docs/monitor/workers.md index 3cb2d3d5..622e3aa3 100644 --- a/documentation/docs/monitor/nodes.md +++ b/documentation/docs/monitor/workers.md @@ -11,20 +11,20 @@ next: --- -# Nodes +# Workers -The [gateway service](../fundamentals/runtime-services#gateway) keeps a list of its active nodes. These can be requested with the nodes API. +The [gateway service](../fundamentals/runtime-services#gateway) keeps a list of its active workers. These can be requested with the workers API. ```http -GET http://gateway.example.com:3000/nodes HTTP/1.1 +GET http://gateway.example.com:3000/workers HTTP/1.1 ``` -This returns a list of registered nodes. Per node the url and procedure names (FQNs) are returned. +This returns a list of registered workers. Per worker the url and procedure names (FQNs) are returned. ```json [ { - "url": "http://node.example.com:3002", + "url": "http://worker.example.com:3002", "procedureNames": [ "procedure1", “procedure2” diff --git a/examples/README.md b/examples/README.md index e4306582..203ea947 100644 --- a/examples/README.md +++ b/examples/README.md @@ -11,7 +11,7 @@ the examples should still be understandable. In order to run the examples you need to have the following installed: -* [Node.js](https://nodejs.org/en/) version 18.7.0 or higher +* [Node.js](https://nodejs.org/en/) version 20.0.0 or higher * [TypeScript](https://www.typescriptlang.org/) version 4.4.2 or higher Most examples do not have an UI to keep them simple and focussed. For running these examples the PRC API will be used. diff --git a/examples/apps/contact-list/README.md b/examples/apps/contact-list/README.md index b096f2cf..0fb7518c 100644 --- a/examples/apps/contact-list/README.md +++ b/examples/apps/contact-list/README.md @@ -35,7 +35,7 @@ Production * Repository (`services/repository.json`) * Gateway (`services/gateway.json`) * Proxy (`services/proxy.json`) -* Node - loads the *server* segment (`services/node.json`) +* Worker - loads the *server* segment (`services/worker.json`) ## Running the example @@ -78,7 +78,7 @@ Note that the Jitar instance needs to run beside Vite, otherwise the backend com ## Running in production -To run the application in production mode, we need four terminal sessions to start the repository, gateway, node and proxy (as webserver) separately. The starting order is of importance. +To run the application in production mode, we need four terminal sessions to start the repository, gateway, worker and proxy (as webserver) separately. The starting order is of importance. **Repository** (terminal 1) @@ -92,10 +92,10 @@ npm run repo npm run gateway ``` -**Node** (terminal 3) +**Worker** (terminal 3) ```bash -npm run node +npm run worker ``` **Proxy** (terminal 4) diff --git a/examples/apps/contact-list/package.json b/examples/apps/contact-list/package.json index 3c630f33..2316d872 100644 --- a/examples/apps/contact-list/package.json +++ b/examples/apps/contact-list/package.json @@ -9,7 +9,7 @@ "standalone": "node --experimental-network-imports dist/jitar.js --config=services/standalone.json", "repo": "node --experimental-network-imports dist/jitar.js --config=services/repository.json", "gateway": "node --experimental-network-imports dist/jitar.js --config=services/gateway.json", - "node": "node --experimental-network-imports dist/jitar.js --config=services/node.json", + "worker": "node --experimental-network-imports dist/jitar.js --config=services/worker.json", "proxy": "node --experimental-network-imports dist/jitar.js --config=services/proxy.json", "preview": "vite preview" }, diff --git a/examples/apps/contact-list/requests.http b/examples/apps/contact-list/requests.http new file mode 100644 index 00000000..48c49f27 --- /dev/null +++ b/examples/apps/contact-list/requests.http @@ -0,0 +1,15 @@ + +GET http://localhost:8080/rpc/domain/contact/getContacts?version=0.0.0&serialize=true HTTP/1.1 + +### + +GET http://localhost:3000/rpc/domain/contact/getContacts?version=0.0.0&serialize=true HTTP/1.1 + +### + +POST http://localhost:3001/rpc/domain/contact/getContacts?version=0.0.0&serialize=true HTTP/1.1 +conent-type: application/json + +{ + +} \ No newline at end of file diff --git a/examples/apps/contact-list/services/node.json b/examples/apps/contact-list/services/worker.json similarity index 96% rename from examples/apps/contact-list/services/node.json rename to examples/apps/contact-list/services/worker.json index 32c92683..0facf29f 100644 --- a/examples/apps/contact-list/services/node.json +++ b/examples/apps/contact-list/services/worker.json @@ -3,7 +3,7 @@ "setUp": ["./integrations/jitar/setUpDatabase"], "tearDown": ["./integrations/jitar/tearDownDatabase"], "healthChecks": ["./integrations/jitar/databaseHealthCheck"], - "node": + "worker": { "gateway": "http://127.0.0.1:3000", "repository": "http://127.0.0.1:2999", diff --git a/examples/concepts/access-protection/package.json b/examples/concepts/access-protection/package.json index d08b3f87..02f2e013 100644 --- a/examples/concepts/access-protection/package.json +++ b/examples/concepts/access-protection/package.json @@ -7,8 +7,8 @@ "standalone": "node --experimental-network-imports --env-file=.env dist/jitar.js --config=services/standalone.json", "repo": "node --experimental-network-imports dist/jitar.js --config=services/repository.json", "gateway": "node --experimental-network-imports --env-file=.env dist/jitar.js --config=services/gateway.json", - "node-web": "node --experimental-network-imports --env-file=.env dist/jitar.js --config=services/web.json", - "node-game": "node --experimental-network-imports --env-file=.env dist/jitar.js --config=services/game.json" + "worker-web": "node --experimental-network-imports --env-file=.env dist/jitar.js --config=services/web.json", + "worker-game": "node --experimental-network-imports --env-file=.env dist/jitar.js --config=services/game.json" }, "dependencies": { "jitar": "^0.6.0" diff --git a/examples/concepts/access-protection/requests.http b/examples/concepts/access-protection/requests.http index 7ac76646..bb507486 100644 --- a/examples/concepts/access-protection/requests.http +++ b/examples/concepts/access-protection/requests.http @@ -12,7 +12,7 @@ content-type: application/json // Run the protected function with key (succeeds) POST http://localhost:3000/rpc/game/checkSecret HTTP/1.1 -X-Jitar-Trust-Key: VERY_SECRET_KEY +X-Jitar-Trust-Key: MY_VERY_SECRET_KEY content-type: application/json { diff --git a/examples/concepts/access-protection/services/game.json b/examples/concepts/access-protection/services/game.json index 0569b862..eb417ea0 100644 --- a/examples/concepts/access-protection/services/game.json +++ b/examples/concepts/access-protection/services/game.json @@ -1,6 +1,6 @@ { "url": "http://127.0.0.1:3002", - "node": + "worker": { "gateway": "http://127.0.0.1:3000", "repository": "http://127.0.0.1:2999", diff --git a/examples/concepts/access-protection/services/web.json b/examples/concepts/access-protection/services/web.json index af103c41..032ce3f5 100644 --- a/examples/concepts/access-protection/services/web.json +++ b/examples/concepts/access-protection/services/web.json @@ -1,6 +1,6 @@ { "url": "http://127.0.0.1:3001", - "node": + "worker": { "gateway": "http://127.0.0.1:3000", "repository": "http://127.0.0.1:2999", diff --git a/examples/concepts/data-transportation/README.md b/examples/concepts/data-transportation/README.md index 86ffff12..1ae88771 100644 --- a/examples/concepts/data-transportation/README.md +++ b/examples/concepts/data-transportation/README.md @@ -50,7 +50,7 @@ npm install npm run build ``` -To start Jitar we need four terminal sessions to start the repository, gateway, and nodes separately. The starting order is of importance. +To start Jitar we need four terminal sessions to start the repository, gateway, and workers separately. The starting order is of importance. **Repository** (terminal 1) @@ -67,13 +67,13 @@ npm run gateway **Account segment** (terminal 3) ```bash -npm run node-account +npm run worker-account ``` **Helpdesk segment** (terminal 4) ```bash -npm run node-helpdesk +npm run worker-helpdesk ``` The ``requests.http`` file contains example request to call the procedures. Note that the Account object is created on the *account* segment. diff --git a/examples/concepts/data-transportation/package.json b/examples/concepts/data-transportation/package.json index d6221a91..ffc59c0f 100644 --- a/examples/concepts/data-transportation/package.json +++ b/examples/concepts/data-transportation/package.json @@ -7,8 +7,8 @@ "standalone": "node --experimental-network-imports dist/jitar.js --config=services/standalone.json", "repo": "node --experimental-network-imports dist/jitar.js --config=services/repository.json", "gateway": "node --experimental-network-imports dist/jitar.js --config=services/gateway.json", - "node-account": "node --experimental-network-imports dist/jitar.js --config=services/account.json", - "node-helpdesk": "node --experimental-network-imports dist/jitar.js --config=services/helpdesk.json" + "worker-account": "node --experimental-network-imports dist/jitar.js --config=services/account.json", + "worker-helpdesk": "node --experimental-network-imports dist/jitar.js --config=services/helpdesk.json" }, "dependencies": { "jitar": "^0.6.0" diff --git a/examples/concepts/data-transportation/services/account.json b/examples/concepts/data-transportation/services/account.json index 2d243224..a3b24553 100644 --- a/examples/concepts/data-transportation/services/account.json +++ b/examples/concepts/data-transportation/services/account.json @@ -1,6 +1,6 @@ { "url": "http://127.0.0.1:3001", - "node": + "worker": { "gateway": "http://127.0.0.1:3000", "repository": "http://127.0.0.1:2999", diff --git a/examples/concepts/data-transportation/services/helpdesk.json b/examples/concepts/data-transportation/services/helpdesk.json index b897a28d..000b9266 100644 --- a/examples/concepts/data-transportation/services/helpdesk.json +++ b/examples/concepts/data-transportation/services/helpdesk.json @@ -1,6 +1,6 @@ { "url": "http://127.0.0.1:3002", - "node": + "worker": { "gateway": "http://127.0.0.1:3000", "repository": "http://127.0.0.1:2999", diff --git a/examples/concepts/error-handling/README.md b/examples/concepts/error-handling/README.md index 408256ce..0da0a65e 100644 --- a/examples/concepts/error-handling/README.md +++ b/examples/concepts/error-handling/README.md @@ -32,8 +32,8 @@ Production * Repository (`services/repository.json`) * Gateway (`services/gateway.json`) -* Data - loads the *contact* segment (`services/node1.json`) -* Process - loads the *organization* segment (`services/node2.json`) +* Data - loads the *contact* segment (`services/data.json`) +* Process - loads the *organization* segment (`services/process.json`) ## Running the example @@ -49,7 +49,7 @@ npm install npm run build ``` -To start Jitar we need four terminal sessions to start the repository, gateway, and nodes separately. The starting order is of importantance. +To start Jitar we need four terminal sessions to start the repository, gateway, and workers separately. The starting order is of importantance. **Repository** (terminal 1) @@ -66,13 +66,13 @@ npm run gateway **Data segment** (terminal 3) ```bash -npm run node-data +npm run worker-data ``` **Process segment** (terminal 4) ```bash -npm run node-process +npm run worker-process ``` The ``requests.http`` file contains example requests to call the procedures. diff --git a/examples/concepts/error-handling/package.json b/examples/concepts/error-handling/package.json index bc1ea531..b3c79fd8 100644 --- a/examples/concepts/error-handling/package.json +++ b/examples/concepts/error-handling/package.json @@ -7,8 +7,8 @@ "standalone": "node --experimental-network-imports dist/jitar.js --config=services/standalone.json", "repo": "node --experimental-network-imports dist/jitar.js --config=services/repository.json", "gateway": "node --experimental-network-imports dist/jitar.js --config=services/gateway.json", - "node-data": "node --experimental-network-imports dist/jitar.js --config=services/data.json", - "node-process": "node --experimental-network-imports dist/jitar.js --config=services/process.json" + "worker-data": "node --experimental-network-imports dist/jitar.js --config=services/data.json", + "worker-process": "node --experimental-network-imports dist/jitar.js --config=services/process.json" }, "dependencies": { "jitar": "^0.6.0" diff --git a/examples/concepts/error-handling/services/data.json b/examples/concepts/error-handling/services/data.json index cd5b90ba..ba463f83 100644 --- a/examples/concepts/error-handling/services/data.json +++ b/examples/concepts/error-handling/services/data.json @@ -1,6 +1,6 @@ { "url": "http://127.0.0.1:3001", - "node": + "worker": { "gateway": "http://127.0.0.1:3000", "repository": "http://127.0.0.1:2999", diff --git a/examples/concepts/error-handling/services/process.json b/examples/concepts/error-handling/services/process.json index 136437dc..ee772123 100644 --- a/examples/concepts/error-handling/services/process.json +++ b/examples/concepts/error-handling/services/process.json @@ -1,6 +1,6 @@ { "url": "http://127.0.0.1:3002", - "node": + "worker": { "gateway": "http://127.0.0.1:3000", "repository": "http://127.0.0.1:2999", diff --git a/examples/concepts/load-balancing/README.md b/examples/concepts/load-balancing/README.md index 4fdd0cc5..74fa60bb 100644 --- a/examples/concepts/load-balancing/README.md +++ b/examples/concepts/load-balancing/README.md @@ -1,7 +1,7 @@ # Jitar | Load Balancing example -This example demonstrates how to load balance application segments by running them on multiple nodes. +This example demonstrates how to load balance application segments by running them on multiple workers. The application contains simple calculator tasks that are placed in a single segment. Each of its functions can be used independently. @@ -29,8 +29,8 @@ Production * Repository (`services/repository.json`) * Gateway (`services/gateway.json`) -* Node 1 - loads the *calculator* segment (`services/node1.json`) -* Node 2 - loads the *calculator* segment (`services/node2.json`) +* Worker 1 - loads the *calculator* segment (`services/worker1.json`) +* Worker 2 - loads the *calculator* segment (`services/worker2.json`) ## Running the example (load balanced) @@ -46,7 +46,7 @@ npm install npm run build ``` -To start Jitar we need four terminal sessions to start the repository, gateway, and nodes separately. The starting order is of importance. +To start Jitar we need four terminal sessions to start the repository, gateway, and workers separately. The starting order is of importance. **Repository** (terminal 1) @@ -60,17 +60,17 @@ npm run repo npm run gateway ``` -**Node 1** (terminal 3) +**Worker 1** (terminal 3) ```bash -npm run node1 +npm run worker1 ``` -**Node 2** (terminal 4) +**Worker 2** (terminal 4) ```bash -npm run node2 +npm run worker2 ``` The ``requests.http`` file contains example request to call the procedure. -Note that the requests are handled round robin by both nodes per procedure. +Note that the requests are handled round robin by both workers per procedure. diff --git a/examples/concepts/load-balancing/package.json b/examples/concepts/load-balancing/package.json index 35f7bf6c..3757a92c 100644 --- a/examples/concepts/load-balancing/package.json +++ b/examples/concepts/load-balancing/package.json @@ -7,8 +7,8 @@ "standalone": "node --experimental-network-imports dist/jitar.js --config=services/standalone.json", "repo": "node --experimental-network-imports dist/jitar.js --config=services/repository.json", "gateway": "node --experimental-network-imports dist/jitar.js --config=services/gateway.json", - "node1": "node --experimental-network-imports dist/jitar.js --config=services/node1.json", - "node2": "node --experimental-network-imports dist/jitar.js --config=services/node2.json" + "worker1": "node --experimental-network-imports dist/jitar.js --config=services/worker1.json", + "worker2": "node --experimental-network-imports dist/jitar.js --config=services/worker2.json" }, "dependencies": { "jitar": "^0.6.0" diff --git a/examples/concepts/load-balancing/services/node1.json b/examples/concepts/load-balancing/services/worker1.json similarity index 92% rename from examples/concepts/load-balancing/services/node1.json rename to examples/concepts/load-balancing/services/worker1.json index db078145..470a3175 100644 --- a/examples/concepts/load-balancing/services/node1.json +++ b/examples/concepts/load-balancing/services/worker1.json @@ -1,6 +1,6 @@ { "url": "http://127.0.0.1:3002", - "node": + "worker": { "gateway": "http://127.0.0.1:3000", "repository": "http://127.0.0.1:2999", diff --git a/examples/concepts/load-balancing/services/node2.json b/examples/concepts/load-balancing/services/worker2.json similarity index 92% rename from examples/concepts/load-balancing/services/node2.json rename to examples/concepts/load-balancing/services/worker2.json index 1d0ce82b..a24aadb1 100644 --- a/examples/concepts/load-balancing/services/node2.json +++ b/examples/concepts/load-balancing/services/worker2.json @@ -1,6 +1,6 @@ { "url": "http://127.0.0.1:3001", - "node": + "worker": { "gateway": "http://127.0.0.1:3000", "repository": "http://127.0.0.1:2999", diff --git a/examples/concepts/segmentation/README.md b/examples/concepts/segmentation/README.md index fa45e408..e191753a 100644 --- a/examples/concepts/segmentation/README.md +++ b/examples/concepts/segmentation/README.md @@ -45,7 +45,7 @@ npm install npm run build ``` -To start Jitar we need four terminal sessions to start the repository, gateway, and nodes separately. The starting order is of importance. +To start Jitar we need four terminal sessions to start the repository, gateway, and workers separately. The starting order is of importance. **Repository** (terminal 1) @@ -62,13 +62,13 @@ npm run gateway **Data segment** (terminal 3) ```bash -npm run node-data +npm run worker-data ``` **Process segment** (terminal 4) ```bash -npm run node-process +npm run worker-process ``` The ``requests.http`` file contains example requests to call the procedures. diff --git a/examples/concepts/segmentation/package.json b/examples/concepts/segmentation/package.json index a7859388..acfbc272 100644 --- a/examples/concepts/segmentation/package.json +++ b/examples/concepts/segmentation/package.json @@ -7,8 +7,8 @@ "standalone": "node --experimental-network-imports dist/jitar.js --config=services/standalone.json", "repo": "node --experimental-network-imports dist/jitar.js --config=services/repository.json", "gateway": "node --experimental-network-imports dist/jitar.js --config=services/gateway.json", - "node-data": "node --experimental-network-imports dist/jitar.js --config=services/data.json", - "node-process": "node --experimental-network-imports dist/jitar.js --config=services/process.json" + "worker-data": "node --experimental-network-imports dist/jitar.js --config=services/data.json", + "worker-process": "node --experimental-network-imports dist/jitar.js --config=services/process.json" }, "dependencies": { "jitar": "^0.6.0" diff --git a/examples/concepts/segmentation/services/data.json b/examples/concepts/segmentation/services/data.json index cd5b90ba..ba463f83 100644 --- a/examples/concepts/segmentation/services/data.json +++ b/examples/concepts/segmentation/services/data.json @@ -1,6 +1,6 @@ { "url": "http://127.0.0.1:3001", - "node": + "worker": { "gateway": "http://127.0.0.1:3000", "repository": "http://127.0.0.1:2999", diff --git a/examples/concepts/segmentation/services/process.json b/examples/concepts/segmentation/services/process.json index 136437dc..ee772123 100644 --- a/examples/concepts/segmentation/services/process.json +++ b/examples/concepts/segmentation/services/process.json @@ -1,6 +1,6 @@ { "url": "http://127.0.0.1:3002", - "node": + "worker": { "gateway": "http://127.0.0.1:3000", "repository": "http://127.0.0.1:2999", diff --git a/migrations/migrate-from-0.6.x-to-0.7.x.md b/migrations/migrate-from-0.6.x-to-0.7.x.md index 755da92c..4dc618cf 100644 --- a/migrations/migrate-from-0.6.x-to-0.7.x.md +++ b/migrations/migrate-from-0.6.x-to-0.7.x.md @@ -5,3 +5,77 @@ The 0.7 version of Jitar introduces breaking changes. All changes are described ## Removed support for Node 18 and 19 The configuration now works with environment variables. This makes it easier and safer to configure the runtime services. But for reading the values in Node, the out-of-the-box .env capability of Node is used. Node 20 is the first version of Node that supports this. We've removed the support for the older versions of Node. + +## Renamed the `node` service to `worker` + +The name `node` was confusing, because each and every service in the cluster is a node. We've renamed the service to `worker` to make it more clear what it does. A couple of things have changed. + +### Service configuration + +The service configuration for a worker looked like this: +```json +{ + "url": "https://node.example.com", + "node": + { + "gateway": "https://gateway.example.com", + "repository": "https://repository.example.com", + "segments": [ "hello" ] + } +} +``` +And now looks like the following: + +```json +{ + "url": "https://worker.example.com", + "worker": + { + "gateway": "https://gateway.example.com", + "repository": "https://repository.example.com", + "segments": [ "hello" ] + } +} +``` + +The configuration for the `proxy` service has changed in the same way. + +Previously, it looked like this: + +```json +{ + "url": "https://proxy.example.com", + "proxy": + { + "repository": "https://repository.example.com", + "node": "https://node.example.com" + } +} +``` + +And now it looks like the following: + +```json +{ + "url": "https://proxy.example.com", + "proxy": + { + "repository": "https://repository.example.com", + "worker": "https://worker.example.com" + } +} +``` + +### Worker api + +The gateway service has some external apis that can be used to get an overview of all registered workers. The url of these apis has changed from `/nodes` to `/workers`. + +The previous url was: +```http +https://gateway.example.com/nodes +``` + +The new url is: +```http +https://gateway.example.com/workers +``` diff --git a/packages/caching/src/building/SegmentCacheWriter.ts b/packages/caching/src/building/SegmentCacheWriter.ts index 0fb7d0f1..724c0de1 100644 --- a/packages/caching/src/building/SegmentCacheWriter.ts +++ b/packages/caching/src/building/SegmentCacheWriter.ts @@ -1,6 +1,6 @@ import { ReflectionDestructuredArray, ReflectionDestructuredObject, ReflectionField, ReflectionFunction, ReflectionParameter } from '@jitar/reflection'; -import { FileManager, VersionParser, createNodeFilename, createRepositoryFilename } from '@jitar/runtime'; +import { FileManager, VersionParser, createWorkerFilename, createRepositoryFilename } from '@jitar/runtime'; import SegmentCache from './models/SegmentCache.js'; import SegmentImport from './models/SegmentImport.js'; @@ -18,17 +18,17 @@ export default class SegmentCacheWriter async write(cache: SegmentCache): Promise { return Promise.all([ - this.#writeNodeCache(cache), + this.#writeWorkerCache(cache), this.#writeRepositoryCache(cache) ]).then(() => undefined); } - async #writeNodeCache(cache: SegmentCache): Promise + async #writeWorkerCache(cache: SegmentCache): Promise { const importCode = this.#createImportCode(cache.imports); const segmentCode = this.#createSegmentCode(cache.name, cache.procedures); - const filename = createNodeFilename(cache.name); + const filename = createWorkerFilename(cache.name); const code = `${importCode}\n${segmentCode}`; return this.#fileManager.write(filename, code); diff --git a/packages/caching/test/_fixtures/CacheFiles.fixture.ts b/packages/caching/test/_fixtures/CacheFiles.fixture.ts index 84180c23..75ad216e 100644 --- a/packages/caching/test/_fixtures/CacheFiles.fixture.ts +++ b/packages/caching/test/_fixtures/CacheFiles.fixture.ts @@ -6,7 +6,7 @@ const ORDER_SEGMENT_REPOSITORY = `export const files = [ \t"order/storeOrder.js" ];`; -const ORDER_SEGMENT_NODE = +const ORDER_SEGMENT_WORKER = `const { default : $1 } = await __import("./order/createOrder.js", "application", false); const { v0_0_0 : $2, v1_0_0 : $3 } = await __import("./order/storeOrder.js", "application", false); const { Segment, Procedure, Implementation, Version, NamedParameter, ArrayParameter, ObjectParameter } = await __import("jitar", "runtime", false); @@ -23,7 +23,7 @@ const PRODUCT_SEGMENT_REPOSITORY = `export const files = [ \t"product/getProducts.js" ];`; -const PRODUCT_SEGMENT_NODE = +const PRODUCT_SEGMENT_WORKER = `const { default : $1, searchProducts : $2 } = await __import("./product/getProducts.js", "application", false); const { default : $3, searchProducts : $4 } = await __import("./product/getProducts_v1.js", "application", false); const { Segment, Procedure, Implementation, Version, NamedParameter, ArrayParameter, ObjectParameter } = await __import("jitar", "runtime", false); @@ -149,9 +149,9 @@ Product.source = "./product/models.js";`; const CACHE_FILES = { - './order.segment.node.js': ORDER_SEGMENT_NODE, + './order.segment.worker.js': ORDER_SEGMENT_WORKER, './order.segment.repository.js': ORDER_SEGMENT_REPOSITORY, - './product.segment.node.js': PRODUCT_SEGMENT_NODE, + './product.segment.worker.js': PRODUCT_SEGMENT_WORKER, './product.segment.repository.js': PRODUCT_SEGMENT_REPOSITORY, './order/createOrder.local.js': CREATE_ORDER_LOCAL, './order/createOrder.remote.js': CREATE_ORDER_REMOTE, @@ -167,9 +167,9 @@ const CACHE_FILES = const CACHE_SEGMENT_FILENAMES = [ - './order.segment.node.js', + './order.segment.worker.js', './order.segment.repository.js', - './product.segment.node.js', + './product.segment.worker.js', './product.segment.repository.js', ]; diff --git a/packages/caching/test/_fixtures/building/SegmentCacheWriter.fixture.ts b/packages/caching/test/_fixtures/building/SegmentCacheWriter.fixture.ts index c36d7ba3..dbdaa863 100644 --- a/packages/caching/test/_fixtures/building/SegmentCacheWriter.fixture.ts +++ b/packages/caching/test/_fixtures/building/SegmentCacheWriter.fixture.ts @@ -12,16 +12,16 @@ const OUTPUT = { FILENAMES: { - ORDER_NODE: CACHE_SEGMENT_FILENAMES[0], + ORDER_WORKER: CACHE_SEGMENT_FILENAMES[0], ORDER_REPOSITORY: CACHE_SEGMENT_FILENAMES[1], - PRODUCT_NODE: CACHE_SEGMENT_FILENAMES[2], + PRODUCT_WORKER: CACHE_SEGMENT_FILENAMES[2], PRODUCT_REPOSITORY: CACHE_SEGMENT_FILENAMES[3] }, CONTENT: { - ORDER_NODE: CACHE_FILES[CACHE_SEGMENT_FILENAMES[0]], + ORDER_WORKER: CACHE_FILES[CACHE_SEGMENT_FILENAMES[0]], ORDER_REPOSITORY: CACHE_FILES[CACHE_SEGMENT_FILENAMES[1]], - PRODUCT_NODE: CACHE_FILES[CACHE_SEGMENT_FILENAMES[2]], + PRODUCT_WORKER: CACHE_FILES[CACHE_SEGMENT_FILENAMES[2]], PRODUCT_REPOSITORY: CACHE_FILES[CACHE_SEGMENT_FILENAMES[3]] } }; diff --git a/packages/caching/test/building/SegmentCacheWriter.spec.ts b/packages/caching/test/building/SegmentCacheWriter.spec.ts index 4d282243..b1c39e86 100644 --- a/packages/caching/test/building/SegmentCacheWriter.spec.ts +++ b/packages/caching/test/building/SegmentCacheWriter.spec.ts @@ -24,10 +24,10 @@ describe('building/SegmentCacheWriter', () => const result = fileManager.writtenFiles; expect(result.size).toBe(4); - expect(result.get(OUTPUT.FILENAMES.ORDER_NODE)).toBe(OUTPUT.CONTENT.ORDER_NODE); + expect(result.get(OUTPUT.FILENAMES.ORDER_WORKER)).toBe(OUTPUT.CONTENT.ORDER_WORKER); expect(result.get(OUTPUT.FILENAMES.ORDER_REPOSITORY)).toBe(OUTPUT.CONTENT.ORDER_REPOSITORY); - expect(result.get(OUTPUT.FILENAMES.PRODUCT_NODE)).toBe(OUTPUT.CONTENT.PRODUCT_NODE); + expect(result.get(OUTPUT.FILENAMES.PRODUCT_WORKER)).toBe(OUTPUT.CONTENT.PRODUCT_WORKER); expect(result.get(OUTPUT.FILENAMES.PRODUCT_REPOSITORY)).toBe(OUTPUT.CONTENT.PRODUCT_REPOSITORY); }); }); diff --git a/packages/create-jitar/templates/jitar-only/services/hello.json b/packages/create-jitar/templates/jitar-only/services/hello.json index 3389493a..c852e801 100644 --- a/packages/create-jitar/templates/jitar-only/services/hello.json +++ b/packages/create-jitar/templates/jitar-only/services/hello.json @@ -1,6 +1,6 @@ { "url": "http://127.0.0.1:3002", - "node": + "worker": { "gateway": "http://127.0.0.1:3000", "repository": "http://127.0.0.1:2999", diff --git a/packages/create-jitar/templates/jitar-only/services/hi.json b/packages/create-jitar/templates/jitar-only/services/hi.json index 9bebcb9f..f85a4a8a 100644 --- a/packages/create-jitar/templates/jitar-only/services/hi.json +++ b/packages/create-jitar/templates/jitar-only/services/hi.json @@ -1,6 +1,6 @@ { "url": "http://127.0.0.1:3001", - "node": + "worker": { "gateway": "http://127.0.0.1:3000", "repository": "http://127.0.0.1:2999", diff --git a/packages/jitar/src/client.ts b/packages/jitar/src/client.ts index da3c725b..65abe637 100644 --- a/packages/jitar/src/client.ts +++ b/packages/jitar/src/client.ts @@ -31,7 +31,7 @@ export MissingParameterValue, ModuleNotAccessible, ModuleNotLoaded, - NoNodeAvailable, + NoWorkerAvailable, ProcedureNotAccessible, ProcedureNotFound, RepositoryNotAvailable, diff --git a/packages/runtime/src/RuntimeBuilder.ts b/packages/runtime/src/RuntimeBuilder.ts index c4b12d34..c41cb1bf 100644 --- a/packages/runtime/src/RuntimeBuilder.ts +++ b/packages/runtime/src/RuntimeBuilder.ts @@ -9,8 +9,8 @@ import LocalRepository from './services/LocalRepository.js'; import RemoteGateway from './services/RemoteGateway.js'; import LocalGateway from './services/LocalGateway.js'; -import RemoteNode from './services/RemoteNode.js'; -import LocalNode from './services/LocalNode.js'; +import RemoteWorker from './services/RemoteWorker.js'; +import LocalWorker from './services/LocalWorker.js'; import Proxy from './services/Proxy.js'; import Standalone from './services/Standalone.js'; @@ -27,7 +27,7 @@ export default class RuntimeBuilder #repository?: RemoteRepository; #gateway?: RemoteGateway; - #node?: RemoteNode; + #worker?: RemoteWorker; url(url?: string): this { @@ -98,9 +98,9 @@ export default class RuntimeBuilder return this; } - node(url?: string): this + worker(url?: string): this { - this.#node = url !== undefined ? new RemoteNode(url) : undefined; + this.#worker = url !== undefined ? new RemoteWorker(url) : undefined; return this; } @@ -135,26 +135,26 @@ export default class RuntimeBuilder return gateway; } - buildNode(trustKey?: string): LocalNode + buildWorker(trustKey?: string): LocalWorker { if (this.#repository === undefined) { - throw new RuntimeNotBuilt('Repository is not set for the node'); + throw new RuntimeNotBuilt('Repository is not set for the worker'); } - const node = new LocalNode(this.#repository, this.#gateway, this.#url, trustKey); - node.segmentNames = this.#segments; - node.healthCheckFiles = this.#healthChecks; - node.middlewareFiles = this.#middlewares; + const worker = new LocalWorker(this.#repository, this.#gateway, this.#url, trustKey); + worker.segmentNames = this.#segments; + worker.healthCheckFiles = this.#healthChecks; + worker.middlewareFiles = this.#middlewares; this.#repository.segmentNames = this.#segments; if (this.gateway !== undefined) { - (this.#gateway as RemoteGateway).node = node; + (this.#gateway as RemoteGateway).worker = worker; } - return node; + return worker; } buildProxy(): Proxy @@ -164,11 +164,11 @@ export default class RuntimeBuilder throw new RuntimeNotBuilt('Repository is not set for the proxy'); } - const runner = this.#gateway ?? this.#node; + const runner = this.#gateway ?? this.#worker; if (runner === undefined) { - throw new RuntimeNotBuilt('Runner (gateway or node) is not set for the proxy'); + throw new RuntimeNotBuilt('Runner (gateway or worker) is not set for the proxy'); } const proxy = new Proxy(this.#repository, runner, this.#url); @@ -190,10 +190,10 @@ export default class RuntimeBuilder repository.assets = this.#assets; repository.overrides = this.#overrides; - const node = new LocalNode(repository, this.#gateway, this.#url, trustKey); - node.segmentNames = this.#segments; + const worker = new LocalWorker(repository, this.#gateway, this.#url, trustKey); + worker.segmentNames = this.#segments; - const standalone = new Standalone(repository, node, this.#url); + const standalone = new Standalone(repository, worker, this.#url); standalone.healthCheckFiles = this.#healthChecks; standalone.middlewareFiles = this.#middlewares; diff --git a/packages/runtime/src/client.ts b/packages/runtime/src/client.ts index bac9a2f1..c3c4d956 100644 --- a/packages/runtime/src/client.ts +++ b/packages/runtime/src/client.ts @@ -1,31 +1,31 @@ -import LocalNode from './services/LocalNode.js'; +import LocalWorker from './services/LocalWorker.js'; import RemoteGateway from './services/RemoteGateway.js'; import RemoteRepository from './services/RemoteRepository.js'; -let client: LocalNode | undefined = undefined; -const resolvers: ((client: LocalNode) => void)[] = []; +let client: LocalWorker | undefined = undefined; +const resolvers: ((client: LocalWorker) => void)[] = []; -export async function startClient(remoteUrl: string, segmentNames: string[] = [], middlewares: string[] = []): Promise +export async function startClient(remoteUrl: string, segmentNames: string[] = [], middlewares: string[] = []): Promise { const repository = new RemoteRepository(remoteUrl); const gateway = new RemoteGateway(remoteUrl); - const node = new LocalNode(repository, gateway); - node.segmentNames = new Set(segmentNames); - node.middlewareFiles = new Set(middlewares); + const worker = new LocalWorker(repository, gateway); + worker.segmentNames = new Set(segmentNames); + worker.middlewareFiles = new Set(middlewares); - await node.start(); + await worker.start(); - client = node; + client = worker; - resolvers.forEach((resolve) => resolve(node)); + resolvers.forEach((resolve) => resolve(worker)); resolvers.length = 0; - return node; + return worker; } -export async function getClient(): Promise +export async function getClient(): Promise { if (client === undefined) { diff --git a/packages/runtime/src/definitions/Files.ts b/packages/runtime/src/definitions/Files.ts index b2883219..da894e94 100644 --- a/packages/runtime/src/definitions/Files.ts +++ b/packages/runtime/src/definitions/Files.ts @@ -3,7 +3,7 @@ const Files = { MODULE_PATTERN: '**/*.js', SEGMENT_PATTERN: '**/*.segment.json', - NODE_SEGMENT_PATTERN: '**/*.segment.node.js', + WORKER_SEGMENT_PATTERN: '**/*.segment.worker.js', REPOSITORY_SEGMENT_PATTERN: '**/*.segment.repository.js' }; @@ -21,9 +21,9 @@ function convertToRemoteFilename(filename: string): string return filename.replace(EXTENSION_PATTERN, '.remote.js'); } -function createNodeFilename(name: string): string +function createWorkerFilename(name: string): string { - return `./${name}.segment.node.js`; + return `./${name}.segment.worker.js`; } function createRepositoryFilename(name: string): string @@ -36,4 +36,4 @@ function isSegmentFilename(filename: string): boolean return filename.includes('.segment.'); } -export { Files, convertToLocalFilename, convertToRemoteFilename, createNodeFilename, createRepositoryFilename, isSegmentFilename }; +export { Files, convertToLocalFilename, convertToRemoteFilename, createWorkerFilename, createRepositoryFilename, isSegmentFilename }; diff --git a/packages/runtime/src/errors/NoNodeAvailable.ts b/packages/runtime/src/errors/NoWorkerAvailable.ts similarity index 55% rename from packages/runtime/src/errors/NoNodeAvailable.ts rename to packages/runtime/src/errors/NoWorkerAvailable.ts index a104eaaa..c8bc4d64 100644 --- a/packages/runtime/src/errors/NoNodeAvailable.ts +++ b/packages/runtime/src/errors/NoWorkerAvailable.ts @@ -3,13 +3,13 @@ import { Loadable } from '@jitar/serialization'; import ServerError from './generic/ServerError.js'; -export default class NoNodeAvailable extends ServerError +export default class NoWorkerAvailable extends ServerError { #name: string; constructor(name: string) { - super(`No node available for procedure '${name}'`); + super(`No worker available for procedure '${name}'`); this.#name = name; } @@ -17,4 +17,4 @@ export default class NoNodeAvailable extends ServerError get name() { return this.#name; } } -(NoNodeAvailable as Loadable).source = 'RUNTIME_ERROR_LOCATION'; +(NoWorkerAvailable as Loadable).source = 'RUNTIME_ERROR_LOCATION'; diff --git a/packages/runtime/src/lib.ts b/packages/runtime/src/lib.ts index 6957d513..2a4f5159 100644 --- a/packages/runtime/src/lib.ts +++ b/packages/runtime/src/lib.ts @@ -25,7 +25,7 @@ export { default as InvalidVersionNumber } from './errors/InvalidVersionNumber.j export { default as MissingParameterValue } from './errors/MissingParameterValue.js'; export { default as ModuleNotAccessible } from './errors/ModuleNotAccessible.js'; export { default as ModuleNotLoaded } from './errors/ModuleNotLoaded.js'; -export { default as NoNodeAvailable } from './errors/NoNodeAvailable.js'; +export { default as NoWorkerAvailable } from './errors/NoWorkerAvailable.js'; export { default as ProcedureNotAccessible } from './errors/ProcedureNotAccessible.js'; export { default as ProcedureNotFound } from './errors/ProcedureNotFound.js'; export { default as RepositoryNotAvailable } from './errors/RepositoryNotAvailable.js'; @@ -53,14 +53,14 @@ export { default as Version } from './models/Version.js'; // Services export { default as Gateway } from './services/Gateway.js'; export { default as LocalGateway } from './services/LocalGateway.js'; -export { default as LocalNode } from './services/LocalNode.js'; +export { default as LocalWorker } from './services/LocalWorker.js'; export { default as LocalRepository } from './services/LocalRepository.js'; -export { default as Node } from './services/Node.js'; -export { default as NodeMonitor } from './services/NodeMonitor.js'; +export { default as Worker } from './services/Worker.js'; +export { default as WorkerMonitor } from './services/WorkerMonitor.js'; export { default as ProcedureRuntime } from './services/ProcedureRuntime.js'; export { default as Proxy } from './services/Proxy.js'; export { default as Remote } from './services/Remote.js'; -export { default as RemoteNode } from './services/RemoteNode.js'; +export { default as RemoteWorker } from './services/RemoteWorker.js'; export { default as RemoteGateway } from './services/RemoteGateway.js'; export { default as RemoteRepository } from './services/RemoteRepository.js'; export { default as Repository } from './services/Repository.js'; diff --git a/packages/runtime/src/services/Gateway.ts b/packages/runtime/src/services/Gateway.ts index 0af2e5f2..fcb1c372 100644 --- a/packages/runtime/src/services/Gateway.ts +++ b/packages/runtime/src/services/Gateway.ts @@ -1,8 +1,8 @@ -import Node from './Node.js'; +import Worker from './Worker.js'; import ProcedureRuntime from './ProcedureRuntime.js'; export default abstract class Gateway extends ProcedureRuntime { - abstract addNode(node: Node): Promise; + abstract addWorker(worker: Worker): Promise; } diff --git a/packages/runtime/src/services/LocalGateway.ts b/packages/runtime/src/services/LocalGateway.ts index 40b7348b..0802db28 100644 --- a/packages/runtime/src/services/LocalGateway.ts +++ b/packages/runtime/src/services/LocalGateway.ts @@ -6,14 +6,14 @@ import Request from '../models/Request.js'; import Response from '../models/Response.js'; import Gateway from './Gateway.js'; -import Node from './Node.js'; -import NodeBalancer from './NodeBalancer.js'; +import Worker from './Worker.js'; +import WorkerBalancer from './WorkerBalancer.js'; import Repository from './Repository.js'; export default class LocalGateway extends Gateway { - #nodes: Set = new Set(); - #balancers: Map = new Map(); + #workers: Set = new Set(); + #balancers: Map = new Map(); #trustKey?: string; constructor(repository: Repository, url?: string, trustKey?: string) @@ -23,14 +23,14 @@ export default class LocalGateway extends Gateway this.#trustKey = trustKey; } - get nodes() + get workers() { - return [...this.#nodes.values()]; + return [...this.#workers.values()]; } getProcedureNames(): string[] { - const procedureNames = this.nodes.map(node => node.getProcedureNames()); + const procedureNames = this.workers.map(worker => worker.getProcedureNames()); const uniqueNames = new Set(procedureNames.flat()); return [...uniqueNames.values()]; @@ -43,28 +43,28 @@ export default class LocalGateway extends Gateway return procedureNames.includes(fqn); } - async addNode(node: Node, trustKey?: string): Promise + async addWorker(worker: Worker, trustKey?: string): Promise { if (trustKey !== undefined && this.#trustKey !== trustKey) { throw new InvalidTrustKey(); } - this.#nodes.add(node); + this.#workers.add(worker); - for (const name of node.getProcedureNames()) + for (const name of worker.getProcedureNames()) { const balancer = this.#getOrCreateBalancer(name); - balancer.addNode(node); + balancer.addWorker(worker); } } - removeNode(node: Node): void + removeWorker(worker: Worker): void { - this.#nodes.delete(node); + this.#workers.delete(worker); - for (const name of node.getProcedureNames()) + for (const name of worker.getProcedureNames()) { const balancer = this.#getBalancer(name); @@ -73,22 +73,22 @@ export default class LocalGateway extends Gateway continue; } - balancer.removeNode(node); + balancer.removeWorker(worker); } } - #getBalancer(fqn: string): NodeBalancer | undefined + #getBalancer(fqn: string): WorkerBalancer | undefined { return this.#balancers.get(fqn); } - #getOrCreateBalancer(fqn: string): NodeBalancer + #getOrCreateBalancer(fqn: string): WorkerBalancer { let balancer = this.#getBalancer(fqn); if (balancer === undefined) { - balancer = new NodeBalancer(); + balancer = new WorkerBalancer(); this.#balancers.set(fqn, balancer); } diff --git a/packages/runtime/src/services/LocalRepository.ts b/packages/runtime/src/services/LocalRepository.ts index 95e032d6..8b8320b7 100644 --- a/packages/runtime/src/services/LocalRepository.ts +++ b/packages/runtime/src/services/LocalRepository.ts @@ -152,11 +152,11 @@ export default class LocalRepository extends Repository if (segmentFilename === undefined) { - return this.#readNodeModule(name); + return this.#readWorkerModule(name); } return this.#hasClientSegmentFile(clientId, segmentFilename) - ? this.#readNodeModule(name) + ? this.#readWorkerModule(name) : this.#readRemoteModule(name); } @@ -194,7 +194,7 @@ export default class LocalRepository extends Repository return clientSegmentFiles.some(clientSegmentFilename => segmentFilename.endsWith(clientSegmentFilename)); } - async #readNodeModule(name: string): Promise + async #readWorkerModule(name: string): Promise { const filename = this.#getModuleFilename(name); const file = await this.#readFile(filename); diff --git a/packages/runtime/src/services/LocalNode.ts b/packages/runtime/src/services/LocalWorker.ts similarity index 96% rename from packages/runtime/src/services/LocalNode.ts rename to packages/runtime/src/services/LocalWorker.ts index 0d819fbc..e97e0f59 100644 --- a/packages/runtime/src/services/LocalNode.ts +++ b/packages/runtime/src/services/LocalWorker.ts @@ -1,6 +1,6 @@ import { ExecutionScopes } from '../definitions/ExecutionScope.js'; -import { createNodeFilename } from '../definitions/Files.js'; +import { createWorkerFilename } from '../definitions/Files.js'; import Unauthorized from '../errors/generic/Unauthorized.js'; import ImplementationNotFound from '../errors/ImplementationNotFound.js'; @@ -14,14 +14,14 @@ import Segment from '../models/Segment.js'; import ArgumentConstructor from '../utils/ArgumentConstructor.js'; import Gateway from './Gateway.js'; -import Node from './Node.js'; +import Worker from './Worker.js'; import Repository from './Repository.js'; import { setRuntime } from '../hooks.js'; const JITAR_TRUST_HEADER_KEY = 'X-Jitar-Trust-Key'; -export default class LocalNode extends Node +export default class LocalWorker extends Worker { #gateway?: Gateway; #trustKey?: string; @@ -120,7 +120,7 @@ export default class LocalNode extends Node async #loadSegment(name: string): Promise { - const filename = createNodeFilename(name); + const filename = createWorkerFilename(name); const module = await this.import(filename, ExecutionScopes.APPLICATION); const segment = module.segment as Segment; diff --git a/packages/runtime/src/services/NodeBalancer.ts b/packages/runtime/src/services/NodeBalancer.ts deleted file mode 100644 index b26131d0..00000000 --- a/packages/runtime/src/services/NodeBalancer.ts +++ /dev/null @@ -1,62 +0,0 @@ - -import NoNodeAvailable from '../errors/NoNodeAvailable.js'; - -import Request from '../models/Request.js'; -import Response from '../models/Response.js'; - -import Node from './Node.js'; - -export default class NodeBalancer -{ - #nodes: Node[] = []; - #currentIndex = 0; - - addNode(node: Node): void - { - if (this.#nodes.includes(node)) - { - return; - } - - this.#nodes.push(node); - } - - removeNode(node: Node): void - { - const index = this.#nodes.indexOf(node); - - if (index === -1) - { - return; - } - - this.#nodes.splice(index, 1); - } - - getNextNode(): Node | undefined - { - if (this.#nodes.length === 0) - { - return; - } - - if (this.#currentIndex >= this.#nodes.length) - { - this.#currentIndex = 0; - } - - return this.#nodes[this.#currentIndex++]; - } - - run(request: Request): Promise - { - const node = this.getNextNode(); - - if (node === undefined) - { - throw new NoNodeAvailable(request.fqn); - } - - return node.run(request); - } -} diff --git a/packages/runtime/src/services/Proxy.ts b/packages/runtime/src/services/Proxy.ts index 18f40db5..6bfdd513 100644 --- a/packages/runtime/src/services/Proxy.ts +++ b/packages/runtime/src/services/Proxy.ts @@ -4,15 +4,15 @@ import Request from '../models/Request.js'; import Response from '../models/Response.js'; import RemoteGateway from './RemoteGateway.js'; -import RemoteNode from './RemoteNode.js'; +import RemoteWorker from './RemoteWorker.js'; import RemoteRepository from './RemoteRepository.js'; import ProcedureRuntime from './ProcedureRuntime.js'; export default class Proxy extends ProcedureRuntime { - #runner: RemoteGateway | RemoteNode; + #runner: RemoteGateway | RemoteWorker; - constructor(repository: RemoteRepository, runner: RemoteGateway | RemoteNode, url?: string) + constructor(repository: RemoteRepository, runner: RemoteGateway | RemoteWorker, url?: string) { super(repository, url); diff --git a/packages/runtime/src/services/Remote.ts b/packages/runtime/src/services/Remote.ts index 15519748..406875d7 100644 --- a/packages/runtime/src/services/Remote.ts +++ b/packages/runtime/src/services/Remote.ts @@ -7,7 +7,7 @@ import { default as ResultResponse } from '../models/Response.js'; import RemoteClassLoader from '../utils/RemoteClassLoader.js'; -import Node from './Node.js'; +import Worker from './Worker.js'; const remoteClassLoader = new RemoteClassLoader(); const defaultSerializer = SerializerBuilder.build(remoteClassLoader); @@ -73,14 +73,14 @@ export default class Remote return new Map(Object.entries(health)); } - async addNode(node: Node): Promise + async addWorker(worker: Worker): Promise { - const url = `${this.#url}/nodes`; + const url = `${this.#url}/workers`; const body = { - url: node.url, - procedureNames: node.getProcedureNames(), - trustKey: node.trustKey, + url: worker.url, + procedureNames: worker.getProcedureNames(), + trustKey: worker.trustKey, }; const options = { diff --git a/packages/runtime/src/services/RemoteGateway.ts b/packages/runtime/src/services/RemoteGateway.ts index 02a59847..6fb8e137 100644 --- a/packages/runtime/src/services/RemoteGateway.ts +++ b/packages/runtime/src/services/RemoteGateway.ts @@ -6,13 +6,13 @@ import Response from '../models/Response.js'; import DummyRepository from './DummyRepository.js'; import Gateway from './Gateway.js'; -import Node from './Node.js'; +import Worker from './Worker.js'; import Remote from './Remote.js'; export default class RemoteGateway extends Gateway { #remote: Remote; - #node?: Node; + #worker?: Worker; constructor(url: string) { @@ -21,17 +21,17 @@ export default class RemoteGateway extends Gateway this.#remote = new Remote(url); } - get node() { return this.#node; } + get worker() { return this.#worker; } - set node(node: Node | undefined) { this.#node = node; } + set worker(worker: Worker | undefined) { this.#worker = worker; } async start(): Promise { await super.start(); - if (this.#node !== undefined) + if (this.#worker !== undefined) { - await this.addNode(this.#node); + await this.addWorker(this.#worker); } } @@ -46,9 +46,9 @@ export default class RemoteGateway extends Gateway throw new NotImplemented(); } - addNode(node: Node): Promise + addWorker(worker: Worker): Promise { - return this.#remote.addNode(node); + return this.#remote.addWorker(worker); } run(request: Request): Promise diff --git a/packages/runtime/src/services/RemoteNode.ts b/packages/runtime/src/services/RemoteWorker.ts similarity index 92% rename from packages/runtime/src/services/RemoteNode.ts rename to packages/runtime/src/services/RemoteWorker.ts index 655b7151..cd754272 100644 --- a/packages/runtime/src/services/RemoteNode.ts +++ b/packages/runtime/src/services/RemoteWorker.ts @@ -3,10 +3,10 @@ import Request from '../models/Request.js'; import Response from '../models/Response.js'; import DummyRepository from './DummyRepository.js'; -import Node from './Node.js'; +import Worker from './Worker.js'; import Remote from './Remote.js'; -export default class RemoteNode extends Node +export default class RemoteWorker extends Worker { #remote: Remote; #procedureNames: Set = new Set(); diff --git a/packages/runtime/src/services/Standalone.ts b/packages/runtime/src/services/Standalone.ts index 791f77ed..ce4caf9a 100644 --- a/packages/runtime/src/services/Standalone.ts +++ b/packages/runtime/src/services/Standalone.ts @@ -3,42 +3,42 @@ import File from '../models/File.js'; import Request from '../models/Request.js'; import Response from '../models/Response.js'; -import LocalNode from './LocalNode.js'; +import LocalWorker from './LocalWorker.js'; import LocalRepository from './LocalRepository.js'; import ProcedureRuntime from './ProcedureRuntime.js'; export default class Standalone extends ProcedureRuntime { - #node: LocalNode; + #worker: LocalWorker; - constructor(repository: LocalRepository, node: LocalNode, url?: string) + constructor(repository: LocalRepository, worker: LocalWorker, url?: string) { super(repository, url); - this.#node = node; + this.#worker = worker; } - get node() { return this.#node; } + get worker() { return this.#worker; } async start(): Promise { - // The node will start the repository - await this.#node.start(); + // The worker will start the repository + await this.#worker.start(); await super.start(); } async stop(): Promise { - // The node will stop the repository - await this.#node.stop(); + // The worker will stop the repository + await this.#worker.stop(); await super.stop(); } getProcedureNames(): string[] { - return this.#node.getProcedureNames(); + return this.#worker.getProcedureNames(); } hasProcedure(fqn: string): boolean @@ -65,6 +65,6 @@ export default class Standalone extends ProcedureRuntime run(request: Request): Promise { - return this.#node.run(request); + return this.#worker.run(request); } } diff --git a/packages/runtime/src/services/Node.ts b/packages/runtime/src/services/Worker.ts similarity index 63% rename from packages/runtime/src/services/Node.ts rename to packages/runtime/src/services/Worker.ts index 2ffa6424..00e62b62 100644 --- a/packages/runtime/src/services/Node.ts +++ b/packages/runtime/src/services/Worker.ts @@ -1,7 +1,7 @@ import ProcedureRuntime from './ProcedureRuntime.js'; -export default abstract class Node extends ProcedureRuntime +export default abstract class Worker extends ProcedureRuntime { abstract get trustKey(): string | undefined; } diff --git a/packages/runtime/src/services/WorkerBalancer.ts b/packages/runtime/src/services/WorkerBalancer.ts new file mode 100644 index 00000000..dedafa51 --- /dev/null +++ b/packages/runtime/src/services/WorkerBalancer.ts @@ -0,0 +1,62 @@ + +import NoWorkerAvailable from '../errors/NoWorkerAvailable.js'; + +import Request from '../models/Request.js'; +import Response from '../models/Response.js'; + +import Worker from './Worker.js'; + +export default class WorkerBalancer +{ + #workers: Worker[] = []; + #currentIndex = 0; + + addWorker(worker: Worker): void + { + if (this.#workers.includes(worker)) + { + return; + } + + this.#workers.push(worker); + } + + removeWorker(worker: Worker): void + { + const index = this.#workers.indexOf(worker); + + if (index === -1) + { + return; + } + + this.#workers.splice(index, 1); + } + + getNextWorker(): Worker | undefined + { + if (this.#workers.length === 0) + { + return; + } + + if (this.#currentIndex >= this.#workers.length) + { + this.#currentIndex = 0; + } + + return this.#workers[this.#currentIndex++]; + } + + run(request: Request): Promise + { + const worker = this.getNextWorker(); + + if (worker === undefined) + { + throw new NoWorkerAvailable(request.fqn); + } + + return worker.run(request); + } +} diff --git a/packages/runtime/src/services/NodeMonitor.ts b/packages/runtime/src/services/WorkerMonitor.ts similarity index 64% rename from packages/runtime/src/services/NodeMonitor.ts rename to packages/runtime/src/services/WorkerMonitor.ts index 6b6d61c7..f1ed8702 100644 --- a/packages/runtime/src/services/NodeMonitor.ts +++ b/packages/runtime/src/services/WorkerMonitor.ts @@ -1,10 +1,10 @@ import LocalGateway from './LocalGateway.js'; -import Node from './Node.js'; +import Worker from './Worker.js'; const DEFAULT_FREQUENCY = 5000; -export default class NodeMonitor +export default class WorkerMonitor { #gateway: LocalGateway; #frequency: number; @@ -33,27 +33,27 @@ export default class NodeMonitor async #monitor(): Promise { - const nodes = this.#gateway.nodes; - const promises = nodes.map(async (node: Node) => this.#monitorNode(node)); + const workers = this.#gateway.workers; + const promises = workers.map(async (worker: Worker) => this.#monitorWorker(worker)); await Promise.all(promises); } - async #monitorNode(node: Node): Promise + async #monitorWorker(worker: Worker): Promise { - const available = await this.#checkNodeAvailable(node); + const available = await this.#checkWorkerAvailable(worker); if (available === false) { - this.#gateway.removeNode(node); + this.#gateway.removeWorker(worker); } } - async #checkNodeAvailable(node: Node): Promise + async #checkWorkerAvailable(worker: Worker): Promise { try { - return await node.isHealthy(); + return await worker.isHealthy(); } catch (error) { diff --git a/packages/runtime/test/_fixtures/services/LocalGateway.fixture.ts b/packages/runtime/test/_fixtures/services/LocalGateway.fixture.ts index bad2ecec..134071a5 100644 --- a/packages/runtime/test/_fixtures/services/LocalGateway.fixture.ts +++ b/packages/runtime/test/_fixtures/services/LocalGateway.fixture.ts @@ -2,24 +2,24 @@ import LocalGateway from '../../../src/services/LocalGateway'; import { REPOSITORIES } from './LocalRepository.fixture'; -import { NODES } from './LocalNode.fixture'; +import { WORKERS } from './LocalWorker.fixture'; const GATEWAY_URL = 'http://localhost:80'; const standaloneGateway = new LocalGateway(REPOSITORIES.DUMMY, GATEWAY_URL); -standaloneGateway.addNode(NODES.SINGLE); +standaloneGateway.addWorker(WORKERS.SINGLE); const distributedGateway = new LocalGateway(REPOSITORIES.DUMMY, GATEWAY_URL); -distributedGateway.addNode(NODES.FIRST); -distributedGateway.addNode(NODES.SECOND); +distributedGateway.addWorker(WORKERS.FIRST); +distributedGateway.addWorker(WORKERS.SECOND); const healthGateway = new LocalGateway(REPOSITORIES.DUMMY, GATEWAY_URL); -healthGateway.addNode(NODES.GOOD); -healthGateway.addNode(NODES.BAD); +healthGateway.addWorker(WORKERS.GOOD); +healthGateway.addWorker(WORKERS.BAD); const protectedGateway = new LocalGateway(REPOSITORIES.DUMMY, GATEWAY_URL, 'MY_PROTECTED_ACCESS_KEY'); -protectedGateway.addNode(NODES.FIRST, 'MY_PROTECTED_ACCESS_KEY'); -protectedGateway.addNode(NODES.SECOND); +protectedGateway.addWorker(WORKERS.FIRST, 'MY_PROTECTED_ACCESS_KEY'); +protectedGateway.addWorker(WORKERS.SECOND); const GATEWAYS = { diff --git a/packages/runtime/test/_fixtures/services/LocalNode.fixture.ts b/packages/runtime/test/_fixtures/services/LocalNode.fixture.ts deleted file mode 100644 index e5cbdbae..00000000 --- a/packages/runtime/test/_fixtures/services/LocalNode.fixture.ts +++ /dev/null @@ -1,39 +0,0 @@ - -import LocalNode from '../../../src/services/LocalNode'; -import { setRuntime } from '../../../src/hooks'; - -import { HEALTH_CHECKS } from '../interfaces/HealthCheck.fixture'; -import { SEGMENTS } from '../models/Segment.fixture'; -import { REPOSITORIES } from './LocalRepository.fixture'; - -const TRUST_KEY = 'MY_TRUST_KEY'; - -const singleNode = new LocalNode(REPOSITORIES.DUMMY, undefined, undefined, TRUST_KEY); -singleNode.addSegment(SEGMENTS.GENERAL); -singleNode.addSegment(SEGMENTS.FIRST); -singleNode.addSegment(SEGMENTS.SECOND); - -const firstNode = new LocalNode(REPOSITORIES.DUMMY); -firstNode.addSegment(SEGMENTS.FIRST); - -const secondNode = new LocalNode(REPOSITORIES.DUMMY); -secondNode.addSegment(SEGMENTS.SECOND); - -const goodNode = new LocalNode(REPOSITORIES.DUMMY); -goodNode.addHealthCheck(HEALTH_CHECKS.GOOD); - -const badNode = new LocalNode(REPOSITORIES.DUMMY); -badNode.addHealthCheck(HEALTH_CHECKS.BAD); - -const NODES = -{ - SINGLE: singleNode, - FIRST: firstNode, - SECOND: secondNode, - GOOD: goodNode, - BAD: badNode -}; - -setRuntime(singleNode); - -export { NODES, TRUST_KEY }; diff --git a/packages/runtime/test/_fixtures/services/LocalWorker.fixture.ts b/packages/runtime/test/_fixtures/services/LocalWorker.fixture.ts new file mode 100644 index 00000000..f922e162 --- /dev/null +++ b/packages/runtime/test/_fixtures/services/LocalWorker.fixture.ts @@ -0,0 +1,39 @@ + +import LocalWorker from '../../../src/services/LocalWorker'; +import { setRuntime } from '../../../src/hooks'; + +import { HEALTH_CHECKS } from '../interfaces/HealthCheck.fixture'; +import { SEGMENTS } from '../models/Segment.fixture'; +import { REPOSITORIES } from './LocalRepository.fixture'; + +const TRUST_KEY = 'MY_TRUST_KEY'; + +const singleWorker = new LocalWorker(REPOSITORIES.DUMMY, undefined, undefined, TRUST_KEY); +singleWorker.addSegment(SEGMENTS.GENERAL); +singleWorker.addSegment(SEGMENTS.FIRST); +singleWorker.addSegment(SEGMENTS.SECOND); + +const firstWorker = new LocalWorker(REPOSITORIES.DUMMY); +firstWorker.addSegment(SEGMENTS.FIRST); + +const secondWorker = new LocalWorker(REPOSITORIES.DUMMY); +secondWorker.addSegment(SEGMENTS.SECOND); + +const goodWorker = new LocalWorker(REPOSITORIES.DUMMY); +goodWorker.addHealthCheck(HEALTH_CHECKS.GOOD); + +const badWorker = new LocalWorker(REPOSITORIES.DUMMY); +badWorker.addHealthCheck(HEALTH_CHECKS.BAD); + +const WORKERS = +{ + SINGLE: singleWorker, + FIRST: firstWorker, + SECOND: secondWorker, + GOOD: goodWorker, + BAD: badWorker +}; + +setRuntime(singleWorker); + +export { WORKERS, TRUST_KEY }; diff --git a/packages/runtime/test/_fixtures/services/NodeBalancer.fixture.ts b/packages/runtime/test/_fixtures/services/NodeBalancer.fixture.ts deleted file mode 100644 index 8ad402ef..00000000 --- a/packages/runtime/test/_fixtures/services/NodeBalancer.fixture.ts +++ /dev/null @@ -1,23 +0,0 @@ - -import LocalNode from '../../../src/services/LocalNode'; -import NodeBalancer from '../../../src/services/NodeBalancer'; - -import { REPOSITORIES } from './LocalRepository.fixture'; - -const NODES = -{ - FIRST: new LocalNode(REPOSITORIES.DUMMY), - SECOND: new LocalNode(REPOSITORIES.DUMMY) -}; - -const filledBalancer = new NodeBalancer(); -filledBalancer.addNode(NODES.FIRST); -filledBalancer.addNode(NODES.SECOND); - -const BALANCERS = -{ - FILLED: filledBalancer, - EMPTY: new NodeBalancer() -}; - -export { BALANCERS, NODES }; diff --git a/packages/runtime/test/_fixtures/services/NodeMonitor.fixture.ts b/packages/runtime/test/_fixtures/services/NodeMonitor.fixture.ts deleted file mode 100644 index f6a7b4b6..00000000 --- a/packages/runtime/test/_fixtures/services/NodeMonitor.fixture.ts +++ /dev/null @@ -1,14 +0,0 @@ - -import NodeMonitor from '../../../src/services/NodeMonitor'; - -import { NODES } from './LocalNode.fixture'; -import { GATEWAYS } from './LocalGateway.fixture'; - -const GATEWAY = GATEWAYS.HEALTH; - -const MONITORS = -{ - HEALTH: new NodeMonitor(GATEWAY, 100) -}; - -export { MONITORS, GATEWAY, NODES }; diff --git a/packages/runtime/test/_fixtures/services/RemoteNode.fixture.ts b/packages/runtime/test/_fixtures/services/RemoteNode.fixture.ts deleted file mode 100644 index f0fb6027..00000000 --- a/packages/runtime/test/_fixtures/services/RemoteNode.fixture.ts +++ /dev/null @@ -1,14 +0,0 @@ - -import RemoteNode from '../../../src/services/RemoteNode'; - -const NODE_URL = 'http://localhost:80'; - -const remoteNode = new RemoteNode(NODE_URL); -remoteNode.procedureNames = new Set(['first', 'second']); - -const NODES = -{ - REMOTE: remoteNode -}; - -export { NODES, NODE_URL }; diff --git a/packages/runtime/test/_fixtures/services/RemoteWorker.fixture.ts b/packages/runtime/test/_fixtures/services/RemoteWorker.fixture.ts new file mode 100644 index 00000000..1fd453a1 --- /dev/null +++ b/packages/runtime/test/_fixtures/services/RemoteWorker.fixture.ts @@ -0,0 +1,14 @@ + +import RemoteWorker from '../../../src/services/RemoteWorker'; + +const WORKER_URL = 'http://localhost:80'; + +const remoteWorker = new RemoteWorker(WORKER_URL); +remoteWorker.procedureNames = new Set(['first', 'second']); + +const WORKERS = +{ + REMOTE: remoteWorker +}; + +export { WORKERS, WORKER_URL }; diff --git a/packages/runtime/test/_fixtures/services/WorkerBalancer.fixture.ts b/packages/runtime/test/_fixtures/services/WorkerBalancer.fixture.ts new file mode 100644 index 00000000..fb12b1aa --- /dev/null +++ b/packages/runtime/test/_fixtures/services/WorkerBalancer.fixture.ts @@ -0,0 +1,23 @@ + +import LocalWorker from '../../../src/services/LocalWorker'; +import WorkerBalancer from '../../../src/services/WorkerBalancer'; + +import { REPOSITORIES } from './LocalRepository.fixture'; + +const WORKERS = +{ + FIRST: new LocalWorker(REPOSITORIES.DUMMY), + SECOND: new LocalWorker(REPOSITORIES.DUMMY) +}; + +const filledBalancer = new WorkerBalancer(); +filledBalancer.addWorker(WORKERS.FIRST); +filledBalancer.addWorker(WORKERS.SECOND); + +const BALANCERS = +{ + FILLED: filledBalancer, + EMPTY: new WorkerBalancer() +}; + +export { BALANCERS, WORKERS }; diff --git a/packages/runtime/test/_fixtures/services/WorkerMonitor.fixture.ts b/packages/runtime/test/_fixtures/services/WorkerMonitor.fixture.ts new file mode 100644 index 00000000..fb15ce67 --- /dev/null +++ b/packages/runtime/test/_fixtures/services/WorkerMonitor.fixture.ts @@ -0,0 +1,14 @@ + +import WorkerMonitor from '../../../src/services/WorkerMonitor'; + +import { WORKERS } from './LocalWorker.fixture'; +import { GATEWAYS } from './LocalGateway.fixture'; + +const GATEWAY = GATEWAYS.HEALTH; + +const MONITORS = +{ + HEALTH: new WorkerMonitor(GATEWAY, 100) +}; + +export { MONITORS, GATEWAY, WORKERS }; diff --git a/packages/runtime/test/services/LocalGateway.spec.ts b/packages/runtime/test/services/LocalGateway.spec.ts index 9ec7a718..59b96b2c 100644 --- a/packages/runtime/test/services/LocalGateway.spec.ts +++ b/packages/runtime/test/services/LocalGateway.spec.ts @@ -58,7 +58,7 @@ describe('services/LocalGateway', () => describe('.run(name, version, parameters)', () => { - it('should find and run a procedure from a node', async () => + it('should find and run a procedure from a worker', async () => { const request = new Request('second', Version.DEFAULT, new Map(), new Map()); const response = await gateway.run(request); @@ -66,7 +66,7 @@ describe('services/LocalGateway', () => expect(response.result).toBe('first'); }); - it('should find and run a procedure from a node that calls a procedure on another node', async () => + it('should find and run a procedure from a worker that calls a procedure on another worker', async () => { const request = new Request('third', Version.DEFAULT, new Map(), new Map()); const response = await gateway.run(request); @@ -83,26 +83,26 @@ describe('services/LocalGateway', () => }); }); - describe('.addNode(node, accessKey)', () => + describe('.addWorker(worker, accessKey)', () => { - it('should not add a node with an incorrect access key', async () => + it('should not add a worker with an incorrect access key', async () => { - const node = gateway.nodes[0]; + const worker = gateway.workers[0]; const protectedGateway = GATEWAYS.PROTECTED; - const addNode = async () => protectedGateway.addNode(node, 'INCORRECT_ACCESS_KEY'); + const addWorker = async () => protectedGateway.addWorker(worker, 'INCORRECT_ACCESS_KEY'); - expect(addNode).rejects.toEqual(new InvalidTrustKey()); + expect(addWorker).rejects.toEqual(new InvalidTrustKey()); }); - it('should not add a node with an access key to an unprotected gateway', async () => + it('should not add a worker with an access key to an unprotected gateway', async () => { - const node = gateway.nodes[0]; + const worker = gateway.workers[0]; const unprotectedGateway = GATEWAYS.STANDALONE; - const addNode = async () => unprotectedGateway.addNode(node, 'NODE_ACCESS_KEY'); + const addWorker = async () => unprotectedGateway.addWorker(worker, 'WORKER_ACCESS_KEY'); - expect(addNode).rejects.toEqual(new InvalidTrustKey()); + expect(addWorker).rejects.toEqual(new InvalidTrustKey()); }); }); }); diff --git a/packages/runtime/test/services/LocalNode.spec.ts b/packages/runtime/test/services/LocalWorker.spec.ts similarity index 76% rename from packages/runtime/test/services/LocalNode.spec.ts rename to packages/runtime/test/services/LocalWorker.spec.ts index 42228191..9c4513db 100644 --- a/packages/runtime/test/services/LocalNode.spec.ts +++ b/packages/runtime/test/services/LocalWorker.spec.ts @@ -5,19 +5,19 @@ import ProcedureNotFound from '../../src/errors/ProcedureNotFound'; import Request from '../../src/models/Request'; import Version from '../../src/models/Version'; -import { NODES, TRUST_KEY } from '../_fixtures/services/LocalNode.fixture'; +import { WORKERS, TRUST_KEY } from '../_fixtures/services/LocalWorker.fixture'; import Unauthorized from '../../src/errors/generic/Unauthorized'; import InvalidTrustKey from '../../src/errors/InvalidTrustKey'; -const node = NODES.SINGLE; +const worker = WORKERS.SINGLE; -describe('services/LocalNode', () => +describe('services/LocalWorker', () => { describe('.isHealthy()', () => { it('should be healthy', async () => { - const healthy = await node.isHealthy(); + const healthy = await worker.isHealthy(); expect(healthy).toBeTruthy(); }); @@ -27,8 +27,8 @@ describe('services/LocalNode', () => { it('should find public procedures', () => { - const hasSecondProcedure = node.hasProcedure('second'); - const hasThirdProcedure = node.hasProcedure('third'); + const hasSecondProcedure = worker.hasProcedure('second'); + const hasThirdProcedure = worker.hasProcedure('third'); expect(hasSecondProcedure).toBeTruthy(); expect(hasThirdProcedure).toBeTruthy(); @@ -36,15 +36,15 @@ describe('services/LocalNode', () => it('should find protected procedures', () => { - const hasProtectedProcedure = node.hasProcedure('protected'); + const hasProtectedProcedure = worker.hasProcedure('protected'); expect(hasProtectedProcedure).toBeTruthy(); }); it('should not find private procedures', () => { - const hasPrivateProcedure = node.hasProcedure('private'); - const hasFirstProcedure = node.hasProcedure('first'); + const hasPrivateProcedure = worker.hasProcedure('private'); + const hasFirstProcedure = worker.hasProcedure('first'); expect(hasPrivateProcedure).toBeFalsy(); expect(hasFirstProcedure).toBeFalsy(); @@ -52,7 +52,7 @@ describe('services/LocalNode', () => it('should not find non-existing procedures', () => { - const hasNonExistingProcedure = node.hasProcedure('nonExisting'); + const hasNonExistingProcedure = worker.hasProcedure('nonExisting'); expect(hasNonExistingProcedure).toBeFalsy(); }); @@ -63,7 +63,7 @@ describe('services/LocalNode', () => it('should run a public procedure that calls a private procedure on the same segment', async () => { const request = new Request('second', Version.DEFAULT, new Map(), new Map()); - const response = await node.run(request); + const response = await worker.run(request); expect(response.result).toBe('first'); }); @@ -71,7 +71,7 @@ describe('services/LocalNode', () => it('should run a public procedure that calls a private procedure on another segment', async () => { const request = new Request('sixth', Version.DEFAULT, new Map(), new Map()); - const response = await node.run(request); + const response = await worker.run(request); expect(response.result).toBe('first'); }); @@ -79,7 +79,7 @@ describe('services/LocalNode', () => it('should run a public procedure that calls a public procedure on another segment', async () => { const request = new Request('third', Version.DEFAULT, new Map(), new Map()); - const response = await node.run(request); + const response = await worker.run(request); expect(response.result).toBe('fourth'); }); @@ -87,7 +87,7 @@ describe('services/LocalNode', () => it('should not run a non-existing procedure', async () => { const request = new Request('nonExisting', Version.DEFAULT, new Map(), new Map()); - const run = async () => node.run(request); + const run = async () => worker.run(request); expect(run).rejects.toEqual(new ProcedureNotFound('nonExisting')); }); @@ -96,7 +96,7 @@ describe('services/LocalNode', () => { const headers = new Map().set('x-jitar-trust-key', TRUST_KEY); const request = new Request('protected', Version.DEFAULT, new Map(), headers); - const response = await node.run(request); + const response = await worker.run(request); expect(response.result).toBe('protected'); }); @@ -105,7 +105,7 @@ describe('services/LocalNode', () => { const headers = new Map().set('x-jitar-trust-key', 'invalid'); const request = new Request('protected', Version.DEFAULT, new Map(), headers); - const run = async () => node.run(request); + const run = async () => worker.run(request); expect(run).rejects.toEqual(new InvalidTrustKey()); }); @@ -113,7 +113,7 @@ describe('services/LocalNode', () => it('should not run a protected procedure without trust key', async () => { const request = new Request('protected', Version.DEFAULT, new Map(), new Map()); - const run = async () => node.run(request); + const run = async () => worker.run(request); expect(run).rejects.toEqual(new Unauthorized()); }); diff --git a/packages/runtime/test/services/NodeBalancer.spec.ts b/packages/runtime/test/services/NodeBalancer.spec.ts deleted file mode 100644 index b42a86d3..00000000 --- a/packages/runtime/test/services/NodeBalancer.spec.ts +++ /dev/null @@ -1,41 +0,0 @@ - -import { describe, expect, it } from 'vitest'; - -import NoNodeAvailable from '../../src/errors/NoNodeAvailable'; -import Request from '../../src/models/Request'; -import Version from '../../src/models/Version'; - -import { BALANCERS, NODES } from '../_fixtures/services/NodeBalancer.fixture'; - -const balancer = BALANCERS.FILLED; -const emptyBalancer = BALANCERS.EMPTY; - -describe('services/NodeBalancer', () => -{ - describe('.getNextNode()', () => - { - it('should select nodes round robin', async () => - { - const firstSelectedNode = balancer.getNextNode(); - const secondSelectedNode = balancer.getNextNode(); - const thirdSelectedNode = balancer.getNextNode(); - const fourthSelectedNode = balancer.getNextNode(); - - expect(firstSelectedNode).toBe(NODES.FIRST); - expect(secondSelectedNode).toBe(NODES.SECOND); - expect(thirdSelectedNode).toBe(NODES.FIRST); - expect(fourthSelectedNode).toBe(NODES.SECOND); - }); - }); - - describe('.run(name, version, parameters)', () => - { - it('should throw a node not available error', async () => - { - const request = new Request('nonExisting', Version.DEFAULT, new Map(), new Map()); - const run = async () => emptyBalancer.run(request); - - expect(run).rejects.toEqual(new NoNodeAvailable('nonExisting')); - }); - }); -}); diff --git a/packages/runtime/test/services/NodeMonitor.spec.ts b/packages/runtime/test/services/NodeMonitor.spec.ts deleted file mode 100644 index 038b1d8a..00000000 --- a/packages/runtime/test/services/NodeMonitor.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ - -import { describe, expect, it } from 'vitest'; - -import { MONITORS, GATEWAY, NODES } from '../_fixtures/services/NodeMonitor.fixture'; - -const monitor = MONITORS.HEALTH; - -describe('services/NodeMonitor', () => -{ - describe('.monitor()', () => - { - it('should keep a node and remove a node', async () => - { - const beforeNodes = GATEWAY.nodes; - - expect(beforeNodes.length).toBe(2); - expect(beforeNodes[0]).toBe(NODES.GOOD); - expect(beforeNodes[1]).toBe(NODES.BAD); - - monitor.start(); - await new Promise(resolve => setTimeout(resolve, 300)); - monitor.stop(); - - const afterNodes = GATEWAY.nodes; - - expect(afterNodes.length).toBe(1); - expect(afterNodes[0]).toBe(NODES.GOOD); - }); - }); -}); diff --git a/packages/runtime/test/services/RemoteNode.spec.ts b/packages/runtime/test/services/RemoteWorker.spec.ts similarity index 61% rename from packages/runtime/test/services/RemoteNode.spec.ts rename to packages/runtime/test/services/RemoteWorker.spec.ts index a311bacf..b6174d2d 100644 --- a/packages/runtime/test/services/RemoteNode.spec.ts +++ b/packages/runtime/test/services/RemoteWorker.spec.ts @@ -1,17 +1,17 @@ import { describe, expect, it } from 'vitest'; -import { NODES, NODE_URL } from '../_fixtures/services/RemoteNode.fixture'; +import { WORKERS, WORKER_URL } from '../_fixtures/services/RemoteWorker.fixture'; -const node = NODES.REMOTE; +const worker = WORKERS.REMOTE; -describe('services/RemoteNode', () => +describe('services/RemoteWorker', () => { describe('.url', () => { it('should contain an url', () => { - expect(node.url).toContain(NODE_URL); + expect(worker.url).toContain(WORKER_URL); }); }); @@ -19,7 +19,7 @@ describe('services/RemoteNode', () => { it('should contain all registered procedure', () => { - const names = node.getProcedureNames(); + const names = worker.getProcedureNames(); expect(names).toContain('first'); expect(names).toContain('second'); @@ -30,8 +30,8 @@ describe('services/RemoteNode', () => { it('should find a procedure', () => { - const hasFirstProcedure = node.hasProcedure('first'); - const hasSecondProcedure = node.hasProcedure('second'); + const hasFirstProcedure = worker.hasProcedure('first'); + const hasSecondProcedure = worker.hasProcedure('second'); expect(hasFirstProcedure).toBeTruthy(); expect(hasSecondProcedure).toBeTruthy(); @@ -39,7 +39,7 @@ describe('services/RemoteNode', () => it('should not find a procedure', () => { - const hasNoProcedure = node.hasProcedure('third'); + const hasNoProcedure = worker.hasProcedure('third'); expect(hasNoProcedure).toBeFalsy(); }); diff --git a/packages/runtime/test/services/WorkerBalancer.spec.ts b/packages/runtime/test/services/WorkerBalancer.spec.ts new file mode 100644 index 00000000..3d485309 --- /dev/null +++ b/packages/runtime/test/services/WorkerBalancer.spec.ts @@ -0,0 +1,41 @@ + +import { describe, expect, it } from 'vitest'; + +import NoWorkerAvailable from '../../src/errors/NoWorkerAvailable'; +import Request from '../../src/models/Request'; +import Version from '../../src/models/Version'; + +import { BALANCERS, WORKERS } from '../_fixtures/services/WorkerBalancer.fixture'; + +const balancer = BALANCERS.FILLED; +const emptyBalancer = BALANCERS.EMPTY; + +describe('services/WorkerBalancer', () => +{ + describe('.getNextWorker()', () => + { + it('should select workers round robin', async () => + { + const firstSelectedWorker = balancer.getNextWorker(); + const secondSelectedWorker = balancer.getNextWorker(); + const thirdSelectedWorker = balancer.getNextWorker(); + const fourthSelectedWorker = balancer.getNextWorker(); + + expect(firstSelectedWorker).toBe(WORKERS.FIRST); + expect(secondSelectedWorker).toBe(WORKERS.SECOND); + expect(thirdSelectedWorker).toBe(WORKERS.FIRST); + expect(fourthSelectedWorker).toBe(WORKERS.SECOND); + }); + }); + + describe('.run(name, version, parameters)', () => + { + it('should throw a worker not available error', async () => + { + const request = new Request('nonExisting', Version.DEFAULT, new Map(), new Map()); + const run = async () => emptyBalancer.run(request); + + expect(run).rejects.toEqual(new NoWorkerAvailable('nonExisting')); + }); + }); +}); diff --git a/packages/runtime/test/services/WorkerMonitor.spec.ts b/packages/runtime/test/services/WorkerMonitor.spec.ts new file mode 100644 index 00000000..566b7898 --- /dev/null +++ b/packages/runtime/test/services/WorkerMonitor.spec.ts @@ -0,0 +1,30 @@ + +import { describe, expect, it } from 'vitest'; + +import { MONITORS, GATEWAY, WORKERS } from '../_fixtures/services/WorkerMonitor.fixture'; + +const monitor = MONITORS.HEALTH; + +describe('services/WorkerMonitor', () => +{ + describe('.monitor()', () => + { + it('should keep a worker and remove a worker', async () => + { + const beforeWorkers = GATEWAY.workers; + + expect(beforeWorkers.length).toBe(2); + expect(beforeWorkers[0]).toBe(WORKERS.GOOD); + expect(beforeWorkers[1]).toBe(WORKERS.BAD); + + monitor.start(); + await new Promise(resolve => setTimeout(resolve, 300)); + monitor.stop(); + + const afterWorkers = GATEWAY.workers; + + expect(afterWorkers.length).toBe(1); + expect(afterWorkers[0]).toBe(WORKERS.GOOD); + }); + }); +}); diff --git a/packages/server-nodejs/src/JitarServer.ts b/packages/server-nodejs/src/JitarServer.ts index ac339bff..9cdb667a 100644 --- a/packages/server-nodejs/src/JitarServer.ts +++ b/packages/server-nodejs/src/JitarServer.ts @@ -3,7 +3,7 @@ import express, { Express } from 'express'; import { Server } from 'http'; import { Logger } from 'tslog'; -import { LocalGateway, LocalNode, LocalRepository, Proxy, Runtime, RemoteClassLoader, ExecutionScopes, Standalone } from '@jitar/runtime'; +import { LocalGateway, LocalWorker, LocalRepository, Proxy, Runtime, RemoteClassLoader, ExecutionScopes, Standalone } from '@jitar/runtime'; import { ClassLoader, Serializer, SerializerBuilder, ValueSerializer } from '@jitar/serialization'; import ServerOptions from './configuration/ServerOptions.js'; @@ -16,7 +16,7 @@ import AssetsController from './controllers/AssetsController.js'; import HealthController from './controllers/HealthController.js'; import JitarController from './controllers/JitarController.js'; import ModulesController from './controllers/ModulesController.js'; -import NodesController from './controllers/NodesController.js'; +import WorkerController from './controllers/WorkerController.js'; import ProceduresController from './controllers/ProceduresController.js'; import ProxyController from './controllers/ProxyController.js'; import RPCController from './controllers/RPCController.js'; @@ -159,9 +159,9 @@ export default class JitarServer { this.#addGatewayControllers(this.#runtime); } - else if (this.#configuration.node !== undefined && this.#runtime instanceof LocalNode) + else if (this.#configuration.worker !== undefined && this.#runtime instanceof LocalWorker) { - this.#addNodeControllers(this.#runtime); + this.#addWorkerControllers(this.#runtime); } else if (this.#configuration.proxy !== undefined && this.#runtime instanceof Proxy) { @@ -188,16 +188,16 @@ export default class JitarServer #addGatewayControllers(gateway: LocalGateway): void { - new NodesController(this.#app, gateway, this.#logger); + new WorkerController(this.#app, gateway, this.#logger); new ProceduresController(this.#app, gateway, this.#logger); new RPCController(this.#app, gateway, this.#serializer, this.#logger); } - #addNodeControllers(node: LocalNode): void + #addWorkerControllers(worker: LocalWorker): void { - new HealthController(this.#app, node, this.#logger); - new ProceduresController(this.#app, node, this.#logger); - new RPCController(this.#app, node, this.#serializer, this.#logger); + new HealthController(this.#app, worker, this.#logger); + new ProceduresController(this.#app, worker, this.#logger); + new RPCController(this.#app, worker, this.#serializer, this.#logger); } #addProxyControllers(proxy: Proxy): void @@ -275,9 +275,9 @@ export default class JitarServer #printProcedureInfo() { - const runtime = this.#getRuntime() as LocalNode | Standalone; + const runtime = this.#getRuntime() as LocalWorker | Standalone; - if (runtime instanceof LocalNode === false + if (runtime instanceof LocalWorker === false && runtime instanceof Standalone === false) { return; diff --git a/packages/server-nodejs/src/configuration/ProxyConfiguration.ts b/packages/server-nodejs/src/configuration/ProxyConfiguration.ts index db7c212a..fd977138 100644 --- a/packages/server-nodejs/src/configuration/ProxyConfiguration.ts +++ b/packages/server-nodejs/src/configuration/ProxyConfiguration.ts @@ -5,7 +5,7 @@ import ProcedureRuntimeConfiguration from './ProcedureRuntimeConfiguration'; export const proxySchema = z .object({ - node: z.string().url().optional(), + worker: z.string().url().optional(), gateway: z.string().url().optional(), repository: z.string().url(), middlewares: z.array(z.string()).optional() @@ -13,43 +13,43 @@ export const proxySchema = z .strict() .superRefine((value, ctx) => { - if (value.node === undefined && value.gateway === undefined) + if (value.worker === undefined && value.gateway === undefined) { ctx.addIssue({ code: z.ZodIssueCode.custom, - message: 'Either node or gateway must be defined', - path: ['node', 'gateway'] + message: 'Either worker or gateway must be defined', + path: ['worker', 'gateway'] }); } - if (value.node !== undefined && value.gateway !== undefined) + if (value.worker !== undefined && value.gateway !== undefined) { ctx.addIssue({ code: z.ZodIssueCode.custom, - message: 'Only node or gateway must be defined', - path: ['node', 'gateway'], + message: 'Only worker or gateway must be defined', + path: ['worker', 'gateway'], }); } }) - .transform((value) => new ProxyConfiguration(value.node, value.gateway, value.repository, value.middlewares)); + .transform((value) => new ProxyConfiguration(value.worker, value.gateway, value.repository, value.middlewares)); export default class ProxyConfiguration extends ProcedureRuntimeConfiguration { - #node?: string; + #worker?: string; #gateway?: string; #repository: string; - constructor(node: string | undefined, gateway: string | undefined, repository: string, middlewares?: string[]) + constructor(worker: string | undefined, gateway: string | undefined, repository: string, middlewares?: string[]) { super(middlewares); - this.#node = node; + this.#worker = worker; this.#gateway = gateway; this.#repository = repository; } - get node() { return this.#node; } + get worker() { return this.#worker; } get gateway() { return this.#gateway; } diff --git a/packages/server-nodejs/src/configuration/RuntimeConfiguration.ts b/packages/server-nodejs/src/configuration/RuntimeConfiguration.ts index de85b80e..1482978a 100644 --- a/packages/server-nodejs/src/configuration/RuntimeConfiguration.ts +++ b/packages/server-nodejs/src/configuration/RuntimeConfiguration.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import GatewayConfiguration, { gatewaySchema } from './GatewayConfiguration.js'; -import NodeConfiguration, { nodeSchema } from './NodeConfiguration.js'; +import WorkerConfiguration, { workerSchema } from './WorkerConfiguration.js'; import ProxyConfiguration, { proxySchema } from './ProxyConfiguration.js'; import RepositoryConfiguration, { repositorySchema } from './RepositoryConfiguration.js'; import StandaloneConfiguration, { standaloneSchema } from './StandaloneConfiguration.js'; @@ -16,11 +16,11 @@ export const runtimeSchema = z standalone: standaloneSchema.optional(), repository: repositorySchema.optional(), gateway: gatewaySchema.optional(), - node: nodeSchema.optional(), + worker: workerSchema.optional(), proxy: proxySchema.optional() }) .strict() - .transform((value) => new RuntimeConfiguration(value.url, value.setUp, value.tearDown, value.healthChecks, value.standalone, value.repository, value.gateway, value.node, value.proxy)); + .transform((value) => new RuntimeConfiguration(value.url, value.setUp, value.tearDown, value.healthChecks, value.standalone, value.repository, value.gateway, value.worker, value.proxy)); export default class RuntimeConfiguration { @@ -31,10 +31,10 @@ export default class RuntimeConfiguration #standalone?: StandaloneConfiguration; #repository?: RepositoryConfiguration; #gateway?: GatewayConfiguration; - #node?: NodeConfiguration; + #worker?: WorkerConfiguration; #proxy?: ProxyConfiguration; - constructor(url?: string, setUp?: string[], tearDown?: string[], healthChecks?: string[], standalone?: StandaloneConfiguration, repository?: RepositoryConfiguration, gateway?: GatewayConfiguration, node?: NodeConfiguration, proxy?: ProxyConfiguration) + constructor(url?: string, setUp?: string[], tearDown?: string[], healthChecks?: string[], standalone?: StandaloneConfiguration, repository?: RepositoryConfiguration, gateway?: GatewayConfiguration, worker?: WorkerConfiguration, proxy?: ProxyConfiguration) { this.#url = url; this.#setUp = setUp; @@ -43,7 +43,7 @@ export default class RuntimeConfiguration this.#standalone = standalone; this.#repository = repository; this.#gateway = gateway; - this.#node = node; + this.#worker = worker; this.#proxy = proxy; } @@ -61,7 +61,7 @@ export default class RuntimeConfiguration get gateway() { return this.#gateway; } - get node() { return this.#node; } + get worker() { return this.#worker; } get proxy() { return this.#proxy; } } diff --git a/packages/server-nodejs/src/configuration/NodeConfiguration.ts b/packages/server-nodejs/src/configuration/WorkerConfiguration.ts similarity index 80% rename from packages/server-nodejs/src/configuration/NodeConfiguration.ts rename to packages/server-nodejs/src/configuration/WorkerConfiguration.ts index b986ec50..278e0ef2 100644 --- a/packages/server-nodejs/src/configuration/NodeConfiguration.ts +++ b/packages/server-nodejs/src/configuration/WorkerConfiguration.ts @@ -3,7 +3,7 @@ import { z } from 'zod'; import ProcedureRuntimeConfiguration from './ProcedureRuntimeConfiguration'; -export const nodeSchema = z +export const workerSchema = z .object({ gateway: z.string().url().optional(), repository: z.string().url().optional(), @@ -12,9 +12,9 @@ export const nodeSchema = z trustKey: z.string().optional() }) .strict() - .transform((value) => new NodeConfiguration(value.gateway, value.repository, value.segments, value.middlewares, value.trustKey)); + .transform((value) => new WorkerConfiguration(value.gateway, value.repository, value.segments, value.middlewares, value.trustKey)); -export default class NodeConfiguration extends ProcedureRuntimeConfiguration +export default class WorkerConfiguration extends ProcedureRuntimeConfiguration { #gateway?: string; #repository?: string; diff --git a/packages/server-nodejs/src/controllers/HealthController.ts b/packages/server-nodejs/src/controllers/HealthController.ts index 1519a36c..30425210 100644 --- a/packages/server-nodejs/src/controllers/HealthController.ts +++ b/packages/server-nodejs/src/controllers/HealthController.ts @@ -2,18 +2,18 @@ import express, { Request, Response } from 'express'; import { Logger } from 'tslog'; -import { LocalNode, Standalone } from '@jitar/runtime'; +import { LocalWorker, Standalone } from '@jitar/runtime'; import Headers from '../definitions/Headers'; import ContentTypes from '../definitions/ContentTypes'; export default class HealthController { - #node: LocalNode | Standalone; + #worker: LocalWorker | Standalone; #logger: Logger; - constructor(app: express.Application, node: LocalNode | Standalone, logger: Logger) + constructor(app: express.Application, worker: LocalWorker | Standalone, logger: Logger) { - this.#node = node; + this.#worker = worker; this.#logger = logger; app.get('/health', (request: Request, response: Response) => { this.getHealth(request, response); }); @@ -22,7 +22,7 @@ export default class HealthController async getHealth(request: Request, response: Response): Promise { - const health = await this.#node.getHealth(); + const health = await this.#worker.getHealth(); const data = Object.fromEntries(health); this.#logger.debug('Got health'); @@ -32,7 +32,7 @@ export default class HealthController async isHealthy(request: Request, response: Response): Promise { - const healthy = await this.#node.isHealthy(); + const healthy = await this.#worker.isHealthy(); this.#logger.debug('Got health status'); diff --git a/packages/server-nodejs/src/controllers/NodesController.ts b/packages/server-nodejs/src/controllers/NodesController.ts deleted file mode 100644 index ce809ef3..00000000 --- a/packages/server-nodejs/src/controllers/NodesController.ts +++ /dev/null @@ -1,71 +0,0 @@ - -import express, { Request, Response } from 'express'; -import { Logger } from 'tslog'; - -import { LocalGateway, RemoteNode } from '@jitar/runtime'; - -import NodeDto, { nodeDtoSchema } from '../models/NodeDto.js'; -import DataConverter from '../utils/DataConverter.js'; -import Headers from '../definitions/Headers.js'; -import ContentTypes from '../definitions/ContentTypes.js'; -import ConversionError from '../errors/ConversionError.js'; - -export default class NodesController -{ - #gateway: LocalGateway; - #logger: Logger; - - constructor(app: express.Application, gateway: LocalGateway, logger: Logger) - { - this.#gateway = gateway; - this.#logger = logger; - - app.get('/nodes', (request: Request, response: Response) => { this.getNodes(request, response); }); - app.post('/nodes', (request: Request, response: Response) => { this.add(request, response); }); - } - - async getNodes(request: Request, response: Response): Promise - { - const nodes = this.#gateway.nodes.map(node => { return { url: node.url, procedureNames: node.getProcedureNames() }; }); - - this.#logger.info('Got nodes'); - - response.setHeader(Headers.CONTENT_TYPE, ContentTypes.JSON); - - return response.status(200).send(nodes); - } - - async add(request: Request, response: Response): Promise - { - try - { - const nodeDto = DataConverter.convert(nodeDtoSchema, request.body); - - const node = new RemoteNode(nodeDto.url); - node.procedureNames = new Set(nodeDto.procedureNames); - - await this.#gateway.addNode(node, nodeDto.trustKey); - - this.#logger.info(`Added node -> ${node.url}`); - - return response.status(201).send(); - } - catch (error: unknown) - { - if (error instanceof ConversionError) - { - const message = error.message; - - this.#logger.warn(`Failed to add node | ${message}`); - - return response.status(400).type('text').send(message); - } - - const message = error instanceof Error ? error.message : 'Internal server error'; - - this.#logger.error(`Failed to add node | ${message}`); - - return response.status(500).type('text').send(message); - } - } -} diff --git a/packages/server-nodejs/src/controllers/ProceduresController.ts b/packages/server-nodejs/src/controllers/ProceduresController.ts index ce2d26c0..7c3dac9e 100644 --- a/packages/server-nodejs/src/controllers/ProceduresController.ts +++ b/packages/server-nodejs/src/controllers/ProceduresController.ts @@ -2,17 +2,17 @@ import express, { Request, Response } from 'express'; import { Logger } from 'tslog'; -import { LocalGateway, LocalNode, Standalone } from '@jitar/runtime'; +import { LocalGateway, LocalWorker, Standalone } from '@jitar/runtime'; import Headers from '../definitions/Headers'; import ContentTypes from '../definitions/ContentTypes'; export default class ProceduresController { - #runtime: LocalGateway | LocalNode | Standalone; + #runtime: LocalGateway | LocalWorker | Standalone; #logger: Logger; - constructor(app: express.Application, runtime: LocalGateway | LocalNode | Standalone, logger: Logger) + constructor(app: express.Application, runtime: LocalGateway | LocalWorker | Standalone, logger: Logger) { this.#runtime = runtime; this.#logger = logger; diff --git a/packages/server-nodejs/src/controllers/WorkerController.ts b/packages/server-nodejs/src/controllers/WorkerController.ts new file mode 100644 index 00000000..634a2ef9 --- /dev/null +++ b/packages/server-nodejs/src/controllers/WorkerController.ts @@ -0,0 +1,71 @@ + +import express, { Request, Response } from 'express'; +import { Logger } from 'tslog'; + +import { LocalGateway, RemoteWorker } from '@jitar/runtime'; + +import WorkerDto, { workerDtoSchema } from '../models/WorkerDto.js'; +import DataConverter from '../utils/DataConverter.js'; +import Headers from '../definitions/Headers.js'; +import ContentTypes from '../definitions/ContentTypes.js'; +import ConversionError from '../errors/ConversionError.js'; + +export default class WorkerController +{ + #gateway: LocalGateway; + #logger: Logger; + + constructor(app: express.Application, gateway: LocalGateway, logger: Logger) + { + this.#gateway = gateway; + this.#logger = logger; + + app.get('/workers', (request: Request, response: Response) => { this.getWorkers(request, response); }); + app.post('/workers', (request: Request, response: Response) => { this.addWorker(request, response); }); + } + + async getWorkers(request: Request, response: Response): Promise + { + const workers = this.#gateway.workers.map(worker => { return { url: worker.url, procedureNames: worker.getProcedureNames() }; }); + + this.#logger.info('Got workers'); + + response.setHeader(Headers.CONTENT_TYPE, ContentTypes.JSON); + + return response.status(200).send(workers); + } + + async addWorker(request: Request, response: Response): Promise + { + try + { + const workerDto = DataConverter.convert(workerDtoSchema, request.body); + + const worker = new RemoteWorker(workerDto.url); + worker.procedureNames = new Set(workerDto.procedureNames); + + await this.#gateway.addWorker(worker, workerDto.trustKey); + + this.#logger.info(`Added worker -> ${worker.url}`); + + return response.status(201).send(); + } + catch (error: unknown) + { + if (error instanceof ConversionError) + { + const message = error.message; + + this.#logger.warn(`Failed to add worker | ${message}`); + + return response.status(400).type('text').send(message); + } + + const message = error instanceof Error ? error.message : 'Internal server error'; + + this.#logger.error(`Failed to add worker | ${message}`); + + return response.status(500).type('text').send(message); + } + } +} diff --git a/packages/server-nodejs/src/models/NodeDto.ts b/packages/server-nodejs/src/models/WorkerDto.ts similarity index 74% rename from packages/server-nodejs/src/models/NodeDto.ts rename to packages/server-nodejs/src/models/WorkerDto.ts index 9997ff56..d578e8ff 100644 --- a/packages/server-nodejs/src/models/NodeDto.ts +++ b/packages/server-nodejs/src/models/WorkerDto.ts @@ -1,16 +1,16 @@ import { z } from 'zod'; -export const nodeDtoSchema = z +export const workerDtoSchema = z .object({ url: z.string().url(), procedureNames: z.array(z.string()).optional(), trustKey: z.string().optional() }) .strict() - .transform((value) => new NodeDto(value.url, value.procedureNames, value.trustKey)); + .transform((value) => new WorkerDto(value.url, value.procedureNames, value.trustKey)); -export default class NodeDto +export default class WorkerDto { url: string; procedureNames: string[]; diff --git a/packages/server-nodejs/src/utils/LocalFileManager.ts b/packages/server-nodejs/src/utils/LocalFileManager.ts index f6dc0a5b..8c06338c 100644 --- a/packages/server-nodejs/src/utils/LocalFileManager.ts +++ b/packages/server-nodejs/src/utils/LocalFileManager.ts @@ -101,9 +101,9 @@ export default class LocalFileManager implements FileManager return glob(`${location}/${pattern}`); } - async getNodeSegmentFiles(): Promise + async getWorkerSegmentFiles(): Promise { - return this.filter('**/*.segment.node.js'); + return this.filter('**/*.segment.worker.js'); } async getRepositorySegmentFiles(): Promise @@ -124,7 +124,7 @@ export default class LocalFileManager implements FileManager #isGeneratedFile(filename: string): boolean { return filename.endsWith('.local.js') - || filename.endsWith('.node.js') + || filename.endsWith('.worker.js') || filename.endsWith('.repository.js') || filename.endsWith('.remote.js'); } diff --git a/packages/server-nodejs/src/utils/RuntimeConfigurator.ts b/packages/server-nodejs/src/utils/RuntimeConfigurator.ts index b4debadb..c94ce72c 100644 --- a/packages/server-nodejs/src/utils/RuntimeConfigurator.ts +++ b/packages/server-nodejs/src/utils/RuntimeConfigurator.ts @@ -1,12 +1,12 @@ -import { Runtime, RuntimeBuilder, LocalRepository, LocalGateway, LocalNode, NodeMonitor, Proxy, Standalone } from '@jitar/runtime'; +import { Runtime, RuntimeBuilder, LocalRepository, LocalGateway, LocalWorker, WorkerMonitor, Proxy, Standalone } from '@jitar/runtime'; import { CacheManager } from '@jitar/caching'; import RuntimeConfiguration from '../configuration/RuntimeConfiguration.js'; import StandaloneConfiguration from '../configuration/StandaloneConfiguration.js'; import RepositoryConfiguration from '../configuration/RepositoryConfiguration.js'; import GatewayConfiguration from '../configuration/GatewayConfiguration.js'; -import NodeConfiguration from '../configuration/NodeConfiguration.js'; +import WorkerConfiguration from '../configuration/WorkerConfiguration.js'; import ProxyConfiguration from '../configuration/ProxyConfiguration.js'; import RuntimeDefaults from '../definitions/RuntimeDefaults.js'; @@ -25,7 +25,7 @@ export default class RuntimeConfigurator if (configuration.standalone !== undefined) return this.#configureStandAlone(url, healthChecks, configuration.standalone); if (configuration.repository !== undefined) return this.#configureRepository(url, healthChecks, configuration.repository); if (configuration.gateway !== undefined) return this.#configureGateway(url, healthChecks, configuration.gateway); - if (configuration.node !== undefined) return this.#configureNode(url, healthChecks, configuration.node); + if (configuration.worker !== undefined) return this.#configureWorker(url, healthChecks, configuration.worker); if (configuration.proxy !== undefined) return this.#configureProxy(url, healthChecks, configuration.proxy); throw new UnknownRuntimeMode(); @@ -43,7 +43,7 @@ export default class RuntimeConfigurator await this.#buildCache(sourceLocation, cacheLocation); const segmentNames = configuration.segments === undefined - ? await this.#getNodeSegmentNames(fileManager) + ? await this.#getWorkerSegmentNames(fileManager) : configuration.segments; const assets = configuration.assets !== undefined @@ -100,12 +100,12 @@ export default class RuntimeConfigurator .repository(repositoryUrl) .buildGateway(trustKey); - new NodeMonitor(gateway, monitorInterval); + new WorkerMonitor(gateway, monitorInterval); return gateway; } - static async #configureNode(url: string, healthChecks: string[], configuration: NodeConfiguration): Promise + static async #configureWorker(url: string, healthChecks: string[], configuration: WorkerConfiguration): Promise { const repositoryUrl = configuration.repository; const gatewayUrl = configuration.gateway; @@ -120,14 +120,14 @@ export default class RuntimeConfigurator .repository(repositoryUrl) .gateway(gatewayUrl) .segment(...segmentNames) - .buildNode(trustKey); + .buildWorker(trustKey); } static async #configureProxy(url: string, healthChecks: string[], configuration: ProxyConfiguration): Promise { const repositoryUrl = configuration.repository; const gatewayUrl = configuration.gateway; - const nodeUrl = configuration.node; + const workerUrl = configuration.worker; const middlewares = configuration.middlewares ?? []; return new RuntimeBuilder() @@ -136,7 +136,7 @@ export default class RuntimeConfigurator .middleware(...middlewares) .repository(repositoryUrl) .gateway(gatewayUrl) - .node(nodeUrl) + .worker(workerUrl) .buildProxy(); } @@ -152,9 +152,9 @@ export default class RuntimeConfigurator await cacheManager.build(); } - static async #getNodeSegmentNames(fileManager: LocalFileManager): Promise + static async #getWorkerSegmentNames(fileManager: LocalFileManager): Promise { - const segmentFilenames = await fileManager.getNodeSegmentFiles(); + const segmentFilenames = await fileManager.getWorkerSegmentFiles(); return segmentFilenames.map(filename => this.#extractSegmentName(filename)); }