👉 Back to contents | 🚀 Getting started | 🥞 Application server layers | 🗃️ Data modeling, storage, and access
Metarhia is a first application server for node.js with native worker threads support for scaling and concurrency domain logic execution.
See configuration application/config/server.js
({
balancer: 8000, // server will create separate thread balancing
ports: [8001, 8002], // server will create separate thread for each port
...
workers: {
pool: 2, // number of threads for domain logic execution
wait: 2000, // timeout to get idle thread from the pool
timeout: 5000, // timeout to execute procedure it thread
},
});
To run procedure in a separate thread use application.invoke
as in example:
const result = await application.invoke({
method: 'lib.invoke1.method1',
args: { key: 'value' },
exclusive: true,
});
console.log({ result });
Invocation of procedures has additional option to control — exclusive
flag. Exclusivity means whether to capture a whole worker thread for execution or a procedure might be processed asynchronously beside the other non-exclusive procedures and tasks at the same thread. That way gives you flexibility in launching practical tasks logic to balance between more stable runtime for critical logic and handling higher workload of small async tasks (evenly spread among threads).
Metarhia provides isolation between users in terms of both state and control flow, and further isolates individual user requests by preventing the mutation of connection states from within the domain logic and API endpoints. The application server employs multiple techniques for code execution isolation: including V8 sandboxing, closures, and worker threads. The primary objectives of this isolation are to enhance security and prevent race conditions. Additionally, isolation helps to safeguard the code through both reference pollution prevention and prototype pollution prevention.
- Use
Console
interface from application code, e.g.console.log('Hello');
See methods in node.js documentation: https://nodejs.org/api/console.html - Log files buffering (lazy write), fetch buffers by timer and by buffer size limit
- Log rotation: keep logs N days, then delete automatically
Just put all static files for browser-side application here: application/static
and server will automatically load files to cache on start except large files (see configs for more details).
Custom error pages: static/.XXX.html
where XXX
is error code, for example: static/.404.html
. You can put different error page templates in different subfolders, for example: static/.500.html
and static/profile/.500.html
, nested folders can override templates.
Virtual path: put template to static/NAME/.virtual.html
where NAME
is directory name or even nested path, for example: static/article/.virtual.html
will be served for example getting /article/programming/javascript
, except truly existing files.
You can schedule a task (function execution) at specific intervals or certain times like here:
const res = await application.scheduler.add({
name: 'name',
every: 'Sep 10th 10s',
args: { i: 2 },
run: 'lib.task1.f1',
});
console.log('Add task', res);
// Output: Add task 2023-10-19-id-0
File application/lib/task1/f1.js
will contain async function like this:
async () => {
console.log('Task started');
await metarhia.metautil.delay(1000);
console.log('Task finished');
};
Task files are JSON files (with name format YYYY-MM-DD-id-N.json
) placed in application/tasks
.
These files will be created and deleted automatically. On the application server start all files will be loaded into a special thread to be executed.
Task file fields:
id: string
- task unique identifier (example:"2021-07-22-id-0"
)name: string
- not unique task nameevery: string
- (example:Jul 22th 100s
), see format belowargs: object
- task arguments (example:{"i":2}
)run: string
- function name to run (example:lib.task1.f1
)
Task file example:
{
"id": "2021-07-22-id-0",
"name": "name",
"every": "Jul 22th 100s",
"args": { "i": 2 },
"run": "lib.task1.f1"
}
Examples for every
field syntax:
Apr 1st
- once at00:00
1st of April15th 100s
- every 100 seconds each 15thSun 17:
- every Sunday at17:00
20th 17:15
- every 20th of any month at17:15
Apr Sun :30
- at HH:30 every hour on Sunday of April2nd :30
- every 2nd of any month at HH:30 every hourSun 3rd 00:
- every Sunday if this day will be 3rd of month at00:00
30m 17s
- interval 30 minutes and 17 secondsSun 5h 30m
- every Sunday with interval 5 hours 30 minutes2021-07-20
- certain date2021-07-20 17:30
- certain date and time
Metarhia uses node.js native test runner to execute tests. You can add tests for application/domain/chat.js
in application/domain/chat.test.js
:
({
name: 'Chat test',
async run(t) {
await t.test('Get room with domain.chat.getRoom', async () => {
const name = 'example1';
const room = await domain.chat.getRoom(name);
node.assert(room);
});
await t.test('Send message with domain.chat.send', async () => {
const result = domain.chat.send('example1', 'Hello there');
node.assert.strictEqual(result, undefined);
});
},
});
Just put all files here: application/resources
. You can get Buffer with file content from code:
const file = application.resources.get(`/fileName.exe`);
You can create start
hook by putting start.js
file to application/domain
, application/db
, or application/lib
:
async () => {
console.log('Code to be executed after start');
};
Application server will stop after:
- Signals:
SIGINT
andSIGTERM
- Keyboard:
Ctrl + C
Before shutdown all stop
hooks will be executed. You can place stop.js
files to application/domain
, application/db
, or application/lib
with async function inside like here:
async () => {
console.log('Code to be executed before stop');
};
👉 Back to contents | 🚀 Getting started | 🥞 Application server layers | 🗃️ Data modeling, storage, and access