Introduction
Welcome to the Proxy Engine Docs! Proxy Engine is an Open Source Node.js Framework created by the team at Cali Style Technologies.
What is Proxy Engine?
Proxy Engine is a modern backend scaffold for node applications built on the flexibility and speed of trails.js which means extending it is easy and intuitive.
Proxy Engine acts as an event management engine for a highly scalable and expandable architecture. It's "event protocol" allows for "plugins" to be easily implemented or ripped out to lighten the burden on development costs without sacrificing ease of use and scalability.
4 Core Features
The goals of Proxy Engine is to be a free form scaffold that focuses on modern enterprise grade applications and testability. Each of these Core Features can be managed via a Worker Profile, allowing you to easily create micro services, or worker instances of your app.
Proxy Engine marshals 4 Core Features:
Events
Events are either emitted or consumed, if an event handler fails, it can retired based on "retry rules". In short: - Publish - Subscribe - Retry
A single Published Event can be consumed by an infinite amount of Subscribers. Subscribers that fail can have an infinite amount of Retries. This can be handy for fixing a bug post morten or if a 3rd party service is unavailable. Events are optionally stored in a database as a "Recorded History". Any event that fails is automatically stored, as well as any retry attempts.
Tasks
Tasks are long running scripts that are processed in a que. For example: processing a video or crunching a large data set. Tasks can publish events, but not consume them. However, an event can trigger the creation of a new task.
Timed Jobs (Cron Jobs)
Timed Jobs are scrips that process at specific times. For example, once an hour, every day at noon, every 3rd wednesday of a month, etc. Timed Jobs can publish events, but not consume them. However, an event can enable or disable a Timed Job. Under the hood, Proxy Engine uses Node Schedule to define when the jobs will be run.
Error Management
Error Management is one of the most important things to remember in development, especially for Node.js applications. Under the hood, Proxy Engine uses Boom to define errors throughout the APIs.
Plugins
Plugins are actually Trails.js "Trailpacks" that are built specifically for Proxy Engine. However, since a Proxy Engine app is at it's core a Trails App, an extensive amount of trailpacks can easily be used.
Currently in the Proxy Engine ecosystem and actively maintained by Cali Style:
- Proxy-Sequelize The default ORM for all Proxy Engine Apps.
- Proxy-Router The Content Router with built in AAA Testing (WIP)
- Proxy-Cart A robust eCommerce Backend
- Proxy-Cart-Countries Default Tax Rate Provider and Shipping Zones validator.
- Proxy-Email A robust Email Management System.
- Proxy-Notifications A robust Notifications System that works with Proxy Email.
- Proxy-CMS A robust Content Management System (WIP)
- Proxy-Analytics A robust Analytics System (WIP)
- Proxy-Sitemap A robust Sitemap Builder (WIP)
- Proxy-Social A robust Social network (WIP)
- Proxy-Permissions A robust ERP level Permissions Systems and Access Control List (ACL)
- Proxy-Generics An adapter protocol for common functions
- Stripe.com Payment Processor
- Authorize.net Payment Processor (WIP)
- GoShippo.com Shipping/Fulfillment Processor (WIP)
- Shipstation.com Shipping/Fulfillment Processor (WIP)
- Taxjar.com Tax Processor (WIP)
- Mandrill Email Provider
- Gcloud Data Store Provider (WIP)
- Google Maps Geolocation Provider (WIP)
- Cloudinary Image Provider (WIP)
- Render Service for rendering HTML or Markdown
Example App
We created a boiler plate to get you started Proxy Engine Example
Dependencies
Supported ORMs
Repo | Build Status (edge) |
---|---|
trailpack-proxy-sequelize |
Supported Webserver
Repo | Build Status (edge) |
---|---|
trailpack-express |
Installation
To install Proxy Engine:
$ npm install trailpack-proxy-engine
If you are using Trail's yo generator:
$ yo trails:trailpack trailpack-proxy-engine
Configuration
To configure Proxy Engine is simple, there are only 2 files to create/modify:
config/main.js
config/main.js
module.exports = {
packs: [
// ... other trailpacks
require('trailpack-proxy-engine')
// ... other proxy-packs
]
}
Like all Trails' trailpacks, it must be included in the config/main.js
file.
config/proxyEngine.js
config/proxyEngine.js
module.exports = {
// If the app is in live mode
live_mode: true,
// If every event should be saved automatically
auto_save: false,
// The worker env profile for this app
profile: 'testProfile',
// Configure Cron Jobs
crons_config: {
// If a Cron class has a 'schedule' method, automatically call it on config.
auto_schedule: true,
// Delay when cron jobs are allowed to start being processed in seconds
uptime_delay: 180,
// The profiles that are able to run specified crons
profiles: {
// If the worker matches `testProfile`, then it's crons can run
testProfile: ['onTestCron.test'],
// If the worker matches `otherProfile`, then it's crons can run
otherProfile: ['otherTestCron.test']
}
},
// Configure Events
events_config: {
// if the Event class has a 'subscribe' method, automatically call it during config.
auto_subscribe: true,
// The profiles that are able to run specified events
profiles: {
// If the worker matches `testProfile`, then it's events can run
testProfile: ['onTestEvent.test'],
// If the worker matches `otherProfile`, then it's events can run
otherProfile: ['otherTestEvent.test']
}
},
// Configure Tasks
tasks_config: {
// The profiles that are able to run specified tasks
profiles: {
// If the worker matches `testProfile`, then it's tasks can run
testProfile: ['TestTask'],
// If the worker matches `otherProfile`, then it's tasks can run
otherProfile: ['OtherTestTask']
}
}
}
Also, Proxy Engine takes it's own config in the config/proxyEngine.js
file.
Config Parameters
Parameter | Type | Default | Description |
---|---|---|---|
live_mode | Boolean | false | If the app is in live mode |
auto_save | Boolean | false | If every Event should be saved |
profile | String | null | The name of this App Instance's profile |
crons_config | Object | {} | The configuration of the Timed Jobs (Cron Jobs) |
events_config | Object | {} | The configuration of the Events |
tasks_config | Object | {} | The configuration of Tasks. |
Tutorial: Event
Proxy Engine events are contained into two base categories: Instance, Global.
Events should always return a promise and resolve (succeed) and return a value or they should reject (throw an error) which will trigger a retry on the burn down schedule.
Instance Events
Instance Events are events that only a single instance in a cluster must deal with. The overwhelming majority of events fall into this category. Mostly, database events, service events etc.
Global Events (TODO)
Global Events are events that every instance in a cluster must respond to. Very few events fall into this category. Mostly, global settings changes, plugin updates, notifications, etc. This requires redis.
Events make it easy to extend functionality without having to edit or change the core of any Proxy Engine Module.
Subscribing to Events
Subscribe takes three arguments:
Argument | Type | Default | Description |
---|---|---|---|
callAgainLocation | String | NONE | The location of the Callback function in dot notation eg. onCustomer.created . This is used when the first try of the event fails. |
eventName | String | NONE | The name of the event to subscribe to eg. customer.created |
func | Function | NONE | The function to execute when this event happens. |
Automatically Subscribing From Profile
Example Profile Config: app/config/proxyEngine.js
module.exports = {
// ... other configuration
profile: 'testProfile',
events_config: {
profiles: {
testProfile: [
'onTestEvent.test3',
'onTestEvent.test4'
],
otherProfile: [
'onTestEvent.test'
]
}
}
}
Alternatively, you can let your profile decide what events it will subscribe to:
Subscribing from a Service
Subscribe to an Event from a Service
// From some service in your app
const ProxyEngineService = this.app.services.ProxyEngineService
// Create a token that you can use later.
const token = ProxyEngineService.subscribe('callAgainLocation', 'eventName', callback)
Also Alternatively, you can subscribe to an event in a service.
Unsubscribe from an Event
Unsubscribe to an Event from a Service
// continued from above
ProxyEngineService.unsubscribe(token)
Once subscribed, to unsubscribe just call the unsubscribe method using the token it was created with.
Creating Event functions
Create events in the /api/events
directory.
Subscribe
Example: api/events/onTestEvent.js
const Event = require('trailpack-proxy-engine').Event
module.exports = class onTestEvent extends Event {
// Subscribe Method is called during the Configuration of the trailpack, regardless of worker profile.
subscribe() {
this.app.services.ProxyEngineService.subscribe('onTestEvent.test','test', this.test)
this.app.services.ProxyEngineService.subscribe('onTestEvent.test2','test2', this.test2)
}
test(msg, data, options) {
// This function will be run when a `test` event is published
return Promise.resolve()
}
test2(msg, data, options) {
// This function will be run when a `test2` event is published
return Promise.reject()
}
}
The subscribe()
method method has reserved functionality and is intended to automatically subscribe instances regardless of their worker profile.
This functionality can be disabled by setting config.proxyEngine.events_config.auto_subscribe
to false.
It's possible to have an instance level cron job gather information from a remote site and change the instance by publishing and event that it is automatically subscribed to.
Tutorial: Task
While event functions respond to events, tasks initiate functions allowed on a specific worker. A common use of a task is a micro-service or a worker environment for example, processing video or any other significant process that should be segregated out to a more adapt worker environment.
Creating Task functions
Create tasks in the /api/tasks
directory.
TODO
Tutorial: Timed Job (Cron)
Creating a Cron
Create cron jobs in the /api/crons
directory. Cron Jobs use node-schedule and are configured per worker profile.
Using the uptime_delay
in the crons_config
can also allow you to delay when cron jobs start to be scheduled. This is useful for when you have an app instance that starts while another is gracefully being shut down.
Schedule Method
Example: api/crons/onTestCron.js
module.exports = class onTestCron extends Cron {
// Schedule Method is called during the Configuration of the trailpack
// Schedule method is reserved to automatically do something regardless of profile.
schedule() {
this.test()
}
test() {
console.log('I have been scheduled')
const j = this.scheduler.scheduleJob('42 * * * *', () => {
console.log('The answer to life, the universe, and everything!')
})
}
}
The schedule()
method has reserved functionality and is intended to automatically schedule other tasks regardless of worker profile. This is useful for cron jobs that do instance level maintenance. It is not recommended to be used for cron jobs that perform global operations.
This feature can be disabled by setting config.proxyEngine.crons_config.auto_schedule
to false.
API: Endpoints
[{
method: ['GET'],
path: '/events',
handler: 'EventController.findAll',
config: {
validate: {
query: {
offset: joi.number(),
limit: joi.number(),
where: joi.object(),
sort: joi.array().items(joi.array()),
}
},
app: {
proxyRouter: {
ignore: true
},
proxyPermissions: {
resource_name: 'apiGetEventsRoute',
roles: ['admin']
}
}
}
},
{
method: ['POST'],
path: '/event',
handler: 'EventController.create',
config: {
app: {
proxyRouter: {
ignore: true
},
proxyPermissions: {
resource_name: 'apiPostEventRoute',
roles: ['admin']
}
}
}
},
{
method: ['GET'],
path: '/event/:id',
handler: 'EventController.findOne',
config: {
validate: {
params: {
id: joi.string().required()
}
},
app: {
proxyRouter: {
ignore: true
},
proxyPermissions: {
resource_name: 'apiGetEventIdRoute',
roles: ['admin']
}
}
}
}]
GET /events
Get a list of Events
Parameter | Type | Description |
---|---|---|
offset | Integer | The offset of records |
limit | Integer | The limit of records to return |
where | Object | The criteria for records to match |
sort | Array | Sequelize order for records to be returned |
POST /event
Create a new Event.
Parameter | Type | Description |
---|
GET /event/:id
Get an Event by ID
Parameter | Type | Description |
---|---|---|
id | Integer | The ID of the event |
API: Controllers
EventController
API: Crons
Example api/crons/index.js
API: Events
Example api/events/index.js
exports.myEvent = require('./myEvent')
Create new Event handlers in the api/events
directory
API: Models
Event
Attribute | Type | Default | Description |
---|
EventSubscribers
Attribute | Type | Default | Description |
---|
API: Services
ProxyEngineService
API: Tasks
Errors
The Proxy Engine API uses the following error codes:
Error Code | Meaning |
---|---|
400 | Bad Request -- Your request sucks. |
401 | Unauthorized -- Your API key is wrong. |
403 | Forbidden -- The requested is hidden for administrators only. |
404 | Not Found -- The specified could not be found. |
405 | Method Not Allowed -- You tried to access a kitten with an invalid method. |
406 | Not Acceptable -- You requested a format that isn't json. |
410 | Gone -- The requested has been removed from our servers. |
418 | I'm a teapot. |
429 | Too Many Requests -- You're requesting too often! Slow down! |
500 | Internal Server Error -- We had a problem with our server. Try again later. |
503 | Service Unavailable -- We're temporarily offline for maintenance. Please try again later. |