增加服务发现功能

This commit is contained in:
zhl 2021-01-30 12:13:42 +08:00
parent 752083f1f5
commit b944d26044
4 changed files with 265 additions and 46 deletions

161
package-lock.json generated
View File

@ -272,6 +272,16 @@
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true
},
"cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"requires": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
"which": "^2.0.1"
}
},
"dateformat": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
@ -290,6 +300,14 @@
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg=="
},
"default-gateway": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz",
"integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==",
"requires": {
"execa": "^5.0.0"
}
},
"denque": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz",
@ -327,6 +345,22 @@
"safe-buffer": "^5.0.1"
}
},
"execa": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz",
"integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==",
"requires": {
"cross-spawn": "^7.0.3",
"get-stream": "^6.0.0",
"human-signals": "^2.1.0",
"is-stream": "^2.0.0",
"merge-stream": "^2.0.0",
"npm-run-path": "^4.0.1",
"onetime": "^5.1.2",
"signal-exit": "^3.0.3",
"strip-final-newline": "^2.0.0"
}
},
"express-fileupload": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/express-fileupload/-/express-fileupload-1.2.0.tgz",
@ -564,6 +598,11 @@
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"get-stream": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz",
"integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg=="
},
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
@ -594,6 +633,11 @@
"toidentifier": "1.0.0"
}
},
"human-signals": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
"integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@ -621,16 +665,50 @@
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"internal-ip": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-6.2.0.tgz",
"integrity": "sha512-D8WGsR6yDt8uq7vDMu7mjcR+yRMm3dW8yufyChmszWRjcSHuxLBkR3GdS2HZAjodsaGuCvXeEJpueisXJULghg==",
"requires": {
"default-gateway": "^6.0.0",
"ipaddr.js": "^1.9.1",
"is-ip": "^3.1.0",
"p-event": "^4.2.0"
}
},
"ip-regex": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz",
"integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q=="
},
"ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
},
"is-ip": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/is-ip/-/is-ip-3.1.0.tgz",
"integrity": "sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==",
"requires": {
"ip-regex": "^4.0.0"
}
},
"is-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
"integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw=="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
},
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@ -770,6 +848,11 @@
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
"optional": true
},
"merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="
},
"middie": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/middie/-/middie-5.2.0.tgz",
@ -793,6 +876,11 @@
"mime-db": "1.45.0"
}
},
"mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
@ -914,6 +1002,14 @@
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz",
"integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw=="
},
"npm-run-path": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
"integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
"requires": {
"path-key": "^3.0.0"
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@ -922,11 +1018,45 @@
"wrappy": "1"
}
},
"onetime": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
"requires": {
"mimic-fn": "^2.1.0"
}
},
"p-event": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz",
"integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==",
"requires": {
"p-timeout": "^3.1.0"
}
},
"p-finally": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
},
"p-timeout": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz",
"integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==",
"requires": {
"p-finally": "^1.0.0"
}
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
},
"path-to-regexp": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.0.tgz",
@ -1118,11 +1248,29 @@
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
},
"shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"requires": {
"shebang-regex": "^3.0.0"
}
},
"shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
},
"sift": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/sift/-/sift-7.0.1.tgz",
"integrity": "sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g=="
},
"signal-exit": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
"integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA=="
},
"sliced": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
@ -1203,6 +1351,11 @@
"integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
"dev": true
},
"strip-final-newline": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
"integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="
},
"tiny-lru": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-7.0.6.tgz",
@ -1292,6 +1445,14 @@
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
},
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"requires": {
"isexe": "^2.0.0"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",

View File

@ -25,6 +25,7 @@
"fastify-jwt": "^2.2.0",
"fastify-plugin": "^3.0.0",
"fs-jetpack": "^4.1.0",
"internal-ip": "^6.2.0",
"mime-types": "^2.1.28",
"mongoose": "5.10.3",
"mongoose-findorcreate": "^3.0.0",

View File

@ -6,57 +6,62 @@ import fastify, {
} from 'fastify'
import helmet from 'fastify-helmet'
import { Server, IncomingMessage, ServerResponse } from 'http'
import {RouterMap} from './decorators/router';
import {mongoose} from "@typegoose/typegoose";
import logger from './logger/logger';
import {Config} from "./cfg/Config";
import {initData} from "./common/GConfig";
import {RouterMap} from './decorators/router'
import {mongoose} from "@typegoose/typegoose"
import logger from './logger/logger'
import {Config} from "./cfg/Config"
import {initData} from "./common/GConfig"
import { RedisClient } from './redis/RedisClient'
import { initRobotCache } from './service/jcfw'
import { error } from './common/Debug'
import {
registerGracefulShutdown,
registService,
unRegistService
} from './utils/system.util'
const zReqParserPlugin = require('./plugins/zReqParser');
const apiAuthPlugin = require('./plugins/apiauth');
const zReqParserPlugin = require('./plugins/zReqParser')
const apiAuthPlugin = require('./plugins/apiauth')
const fs = require('fs');
const join = require('path').join;
const fs = require('fs')
const join = require('path').join
let config: Config = require('../config/config.json');
require('./common/Extend');
let config: Config = require('../config/config.json')
require('./common/Extend')
export class ApiServer {
server: FastifyInstance<Server, IncomingMessage, ServerResponse>;
server: FastifyInstance<Server, IncomingMessage, ServerResponse>
public constructor() {
this.server = fastify({logger: true});
this.registerPlugins();
this.server = fastify({logger: true})
this.registerPlugins()
}
private registerPlugins() {
this.server.register(require('fastify-formbody'));
this.server.register(zReqParserPlugin);
this.server.register(apiAuthPlugin);
this.server.register(require('fastify-formbody'))
this.server.register(zReqParserPlugin)
this.server.register(apiAuthPlugin)
this.server.register(
helmet,
{ hidePoweredBy: false }
)
this.server.register(require('fastify-cors'), {});
this.server.register(require('fastify-cors'), {})
}
private registerRouter() {
logger.log('register api routers');
let self = this;
logger.log('register api routers')
let self = this
for (let [controller, config] of RouterMap.decoratedRouters) {
for(let data of config.data) {
logger.info('find api router', data.method || 'all',
data.path, controller.name);
data.path, controller.name)
// @ts-ignore
self.server[data.method || 'all'](data.path, {
preValidation: async function (request: FastifyRequest, reply: FastifyReply) {
request.roles = config.roles;
await this.apiAuth(request, reply);
request.roles = config.roles
await this.apiAuth(request, reply)
}
}, controller);
}, controller)
}
}
}
@ -64,38 +69,38 @@ export class ApiServer {
* controller
*/
initControllers() {
logger.info('Bootstrap controllers...');
const controllers = join(__dirname, 'controllers');
logger.info('Bootstrap controllers...')
const controllers = join(__dirname, 'controllers')
fs.readdirSync(controllers)
.filter((file: string) => ~file.search(/^[^.].*\.(ts|js)$/))
.forEach((file: any) => {
logger.log(file);
return require(join(controllers, file))});
logger.log(file)
return require(join(controllers, file))})
}
async connectDB() {
const options = {useNewUrlParser: true,
poolSize: 5,
keepAlive: true,
keepAliveInitialDelay: 300000,
useUnifiedTopology: true};
const uri = config.db_main;
logger.info(`connect to ${uri} ...`);
useUnifiedTopology: true}
const uri = config.db_main
logger.info(`connect to ${uri} ...`)
try {
// await mongoose.createConnection(uri, options)
await mongoose.connect(uri, options)
logger.log('DB Connected');
logger.log('DB Connected')
} catch (err) {
logger.log(`DB Connection Error: ${err.message}`);
logger.log(`DB Connection Error: ${err.message}`)
}
let opts = {url: config.redis}
new RedisClient(opts)
}
private setErrHandler() {
this.server.setNotFoundHandler(function(request: any, reply: { send: (arg0: { errcode: number; errmsg: string; }) => void; }){
this.server.setNotFoundHandler(function(request: any, reply: { send: (arg0: { errcode: number, errmsg: string }) => void }){
reply.send({errcode: 404, errmsg: 'page not found'})
});
})
this.server.setErrorHandler(function (error: FastifyError, request: FastifyRequest, reply: FastifyReply) {
let statusCode = error && error.statusCode || 100;
let statusCode = error && error.statusCode || 100
if (statusCode >= 500) {
logger.error(error)
} else if (statusCode >= 400) {
@ -136,24 +141,36 @@ export class ApiServer {
error('error init robot info', err)
}
}
/**
* process意外退出
* @param {boolean} exit
* @param {Error} err
* @return {Promise<void>}
*/
public async gracefullyShutdown(exit: boolean = true, err?: Error) {
await unRegistService(config.port)
}
public async start() {
let self = this;
let self = this
return new Promise(async (resolve, reject) => {
await self.connectDB();
await self.initCache();
self.initControllers();
self.registerRouter();
self.setErrHandler();
self.setFormatSend();
initData();
await registerGracefulShutdown((err) => this.gracefullyShutdown(true, err));
await self.connectDB()
await self.initCache()
await registService(config.port)
self.initControllers()
self.registerRouter()
self.setErrHandler()
self.setFormatSend()
initData()
this.server.listen({port: config.port}, (err: any, address: any) => {
if (err) {
logger.log(err)
process.exit(0)
}
resolve && resolve(address);
resolve && resolve(address)
})
})
});
}

40
src/utils/system.util.ts Normal file
View File

@ -0,0 +1,40 @@
import { RedisClient } from '../redis/RedisClient'
import ip from 'internal-ip'
const signals: NodeJS.Signals[] = ['SIGINT', 'SIGTERM', 'SIGUSR2']
const NODES_SET = 'poker:infosvr'
const discovery_channel = 'poker:infosvr:discovery'
export function registerGracefulShutdown(callback: (err?: Error) => void) {
/**
* Gracefully shutdown on uncaught errors
*/
process.on('uncaughtException', (err) => {
console.error(err)
callback(err)
})
signals.forEach((signal) => {
process.once(signal, () => callback())
})
}
async function getNodeAddress(port: number) {
const host = process.env.SELF_HOSTNAME || await ip.v4()
return `${ host }:${ port }`
}
export async function registService(port: number) {
const address = await getNodeAddress(port)
const client = new RedisClient()
await client.sadd(NODES_SET, address)
await client.publish(discovery_channel, `add,${address}`)
}
export async function unRegistService(port: number) {
const address = await getNodeAddress(port)
const client = new RedisClient()
await client.srem(NODES_SET, address)
await client.publish(discovery_channel, `remove,${address}`)
}