- JavaScript 100%
|
|
||
|---|---|---|
| .forgejo/workflows | ||
| bin | ||
| core | ||
| test | ||
| .gitignore | ||
| .npmrc | ||
| appveyor.yml | ||
| cli.mjs | ||
| exampleconfig.json | ||
| index.mjs | ||
| package.json | ||
| README.md | ||
service-core
Service-Core is a project to faciliate running a node application in production environment on a windows or linux machine. Using Windows Services, Service-Core will register itself and autostart on startup and make sure the application is running. You can also run it as a systemd service in Linux to get the same features. One of the main features of service-core is it being able to take care of maintaining the application including auto updating it seamlessly.
How to use for development
Each application published and pulled from github-like releases needs to have a file index.mjs that contains an exported function called start(). Here's a basic boiler plate code for index.mjs
index.mjs
import fs from 'fs'
import { pathToFileURL } from 'url'
export function start(http, port, ctx) {
// Load our main server and start it
return import('./server.mjs')
.then(function(module) {
let server = new module.default(http, port, ctx)
return server.run()
})
}
// Allows us to run this file directly
if (import.meta.url === pathToFileURL(process.argv[1]).href) {
import('service-core').then(core => {
const port = 5000
var core = new core.ServiceCore('name-of-project-here', import.meta.url, port, '')
// Default dev runtime config
let config = {
NODE_ENV: 'development',
some_config_variable: 'exposed here',
}
let extra = {}
// Optional allow developer to have their own overwrite
if (fs.existsSync('./config.json')) {
extra = JSON.parse(fs.readFileSync('./config.json'))
}
config = {
...config,
...extra,
}
config.port = port
core.setConfig(config)
core.init({ start }).then(function() {
return core.run()
})
})
}
server.mjs
import { Flaska } from 'flaska'
export default class Server {
constructor(http, port, core) {
this.http = http
this.port = port
this.core = core
this.config = Object.assign({}, core.config)
// Use the logger provided by service-core
this.flaskaOptions = {
log: this.core.log,
}
}
run() {
// Create our server
this.flaska = new Flaska(this.flaskaOptions, this.http)
// configure our server
if (this.config.NODE_ENV === 'development') {
this.flaska.devMode()
}
this.flaska.get('/', async (ctx) => {
ctx.body = { version: this.core.app.ctx.version }
})
return this.flaska.listenAsync(this.port).then(() => {
this.core.log.info('Server is listening on port ' + this.port)
})
}
}
How to run as a service
Create a runner file of your choice, ex. runner.mjs with something like this:
import fs from 'fs'
import { runner } from 'service-core'
runner(import.meta.url, 'config.json', 'db.json')
.then(
function(core) {
core.log.info('core is running')
},
function(err) {
runner.log.error(err, 'Error starting runner')
process.exit(1)
}
)
As well as a config file specified above, ex config.json for service-core, something like this for example:
{
"name": "cb",
"cb": {
"http2": true,
"provider": "git",
"url": "https://git.nfp.is/api/v1/repos/thething/compress_benchmark/releases",
"cluster": 1,
"port": 3880,
"scAllowStop": true,
"NODE_ENV": "production"
},
"manager": {
"provider": "git",
"url": "https://git.nfp.is/api/v1/repos/thething/sc-manager/releases",
"port": 4880,
"scAllowStop": false
}
}
Then all you have to do is call node runner.mjs et voila. It will boot up service-core, fetch latest releases from the specified url's and being running, and maintaining it.
Example systemd service file you can use: /etc/systemd/system/myname.service
[Unit]
Description=Service $1
After=network.target
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=1
User=$1
ExecStart=node /home/$1/runner.mjs
WorkingDirectory=/home/$1
StandardOutput=append:/var/log/$1/stdout.log
StandardError=append:/var/log/$1/stderr.log
[Install]
WantedBy=multi-user.target
The Core
The core provides methods for updating applications as well as taking care of restarting and installing and everything needed to have a pleasent experience running a node application in Windows. It auto checks github for new releases based on the repository specified in config.json.
The core supports running two applications by default (specified in config.json file):
- The manage app: Designated UI node app to provide UI interface on top of service-core. Not needed as service-core already does everything by itself but nice to have to remotely read logs and manually trigger updates among other things
- The main app: The main application service-core is designated to run.
Both the main app and manage app get regular update checks and will automatically be installed if a new version is detected.
API
To build a service-core application I recomennd checking out hello world app but in short, all service core applications require the following things:
index.mjsthat exposes a function calledstart(config, db, log, core, http, port)- The application in question must use the passed on
httpparameter to call.createServer(). Otherwise service-core has no way of shutting it down to provide seamless updates among other things.
The start() function gets called with following parameters:
- config: JSON object containing the entirety of
config.json - db: A minimal fork of lowdb database available for the application to use. Also used internally in service-core to manage versions.
- log: A bunyan logger for logging.
- log.event.info,warn,error(message): Write a log message to the windows event viewer.
- core: The internal core. Exposes multiple methods for managing service-core
- http: A wrapped internal node http to call
.createServer(). Allows service-core to monitor the server in question. - port: The port the application should be listening to.