actionhero

Actionhero is a realtime multi-transport nodejs API Server with integrated cluster capabilities and delayed tasks

APACHE-2.0 License

Downloads
14.5K
Stars
2.4K
Committers
127

Bot releases are hidden (Show)

actionhero - v10.1.0 Silence is Golden (logger and initializer updates)

Published by evantahler over 9 years ago

Initializer Callback Errors

You can now return an error in an initializer to the callback. Doing so will crash the actionhero process and log the error. You can do this in any step of the initializer (start, stop, initialize).

screen shot 2015-02-25 at 1 03 51 pm

Log Levels

We now have a trace level of logging which is lower than debug. Many of the resque logs have been moved to this level.

Bugs

Misc

actionhero - v10.0.5

Published by evantahler over 9 years ago

New Features

Bugs Fixed

Misc

actionhero - v10.0.4

Published by evantahler over 9 years ago

v10.0.4

Features

screen shot 2015-02-08 at 12 34 24 pm

Bugs Fixed

Misc

actionhero - v10.0.3: BugFig

Published by evantahler almost 10 years ago

Rename erroneous self reference in client js

actionhero - v10.0.2: BugFix

Published by evantahler almost 10 years ago

  • Enforce the numerical comparison of initializer priorities (rather than string comparisons)
  • Fix an error that improperly detected if a task multiWorker was running and needed to be suspended at shutdown
actionhero - v10.0.1: BugFix

Published by evantahler almost 10 years ago

Fix a poorly named path which prevented actionhero generate from functioning.

actionhero - v10.0.0: Param Validation, initializer order, say hooks, and more!

Published by evantahler almost 10 years ago

actionhero v10.0.0 release notes

Highlights & Breaking Changes

  • you an now define defaults, validation, formatting, and requirements in an action's inputs.
  • new task processor with auto-scaling of parallel taskProcessors
  • new initializer syntax which allows you to now set init, start, and stop priorities
  • new hooks for say within chatrooms, better blocking callbacks for roomAdd and roomLeave (and the depreciation of the previous authentication APIs)
  • New boot options to use multiple config paths / environment variables

Initializers

  • Initializers now look like this:
module.exports = {
  loadPriority:  1000,
  startPriority: 1000,
  stopPriority:  1000,
  initialize: function(api, next){
    api.%%name%% = {};

    next();
  },
  start: function(api, next){
    next();
  },
  stop: function(api, next){
    next();
  }
}
  • This allows us to simplify load order and allow for custom initializers and/or plugins to boot before the core actionhero initializers
  • The module is a single export (module.exports)
  • There are 3 lifecycle events that initializers can respond to: initialize, start, and stop.
    • The _start and _stop methods have been moved to the top level (and renamed to start and stop), along with the initialize method.
    • Each of these methods is passed the api object and a callback.
  • (optionally) have a loadPriority (system levels are > 1000)
  • (optionally) have a startPriority (system levels are > 1000)
  • (optionally) have a stopPriority (system levels are > 1000)

Chat

  • Added a new type of chat middleware, sayCallbacks. This allows you to modify messages being sent to clients, log all messages your self, etc. It is similar in nature to the joinCallbacks and leaveCallbacks.
  • All chat callbacks now process serially.
  • All chat callbacks now require a callback as the final argument:
var chatMiddlewareToAnnounceNewMembers = function(connection, room, callback){
  api.chatRoom.broadcast({}, room, 'I have entered the room: ' + connection.id, function(e){
      callback();
  });
}

api.chatRoom.addJoinCallback(chatMiddlewareToAnnounceNewMembers, 100);

var chatMiddlewareToAnnounceGoneMembers = function(connection, room, callback){
  api.chatRoom.broadcast({}, room, 'I have left the room: ' + connection.id, function(e){
      callback();
  });
}

api.chatRoom.addLeaveCallback(chatMiddlewareToAnnounceGoneMembers, 100);

var middlewareToAddSimleyFacesToAllMessages = function(connection, room, messagePayload, callback){
  messagePayload.message = messagePayload.message + ' :)';
  callback(null, messagePayload);
}

api.chatRoom.addSayCallback(middlewareToAddSimleyFacesToAllMessages, 100);
  • In the example above, I want to announce the member joining the room, but he has not yet been added to the room, as the callback chain is still firing. If the connection itself were to make the broadcast, it would fail because the connection is not in the room. Instead, an empty {} connection is used to proxy the message coming from the 'system'
  • Only the sayCallbacks have a second return value on the callback, messagePayload. This allows you to modify the message being sent to your clients.
  • messagePayload will be modified and and passed on to all addSayCallback middlewares inline, so you can append and modify it as you go
  • If you have a number of callbacks (sayCallbacks, joinCallbacks or leaveCallbacks), the priority maters, and you can block subsequent methods from firing by returning an error to the callback.
// in this example no one will be able to join any room, and the broadcast callback will never be invoked.
api.chatRoom.addJoinCallback(function(connection, room, callback){
  callback(new Error('blocked from joining the room'));
}, 100);

api.chatRoom.addJoinCallback(function(connection, room, callback){
  api.chatRoom.broadcast({}, room, 'I have entered the room: ' + connection.id, function(e){
    callback();
  });
}, 200);
  • If a sayCallback is blocked/errored, the message will simply not be delivered to the client. If a joinCallbacks or leaveCallbacks is blocked/errored, the verb or method used to invoke the call will be returned that error.
  • Because chat middleware can be used to control room access, the previous authentication system has been removed. This new system allows for far greater flexibility in your chat room access rules, including async behavior, such as deferring to a database. You no longer need to pre-load authentication values onto the connections at boot. The following methods are removed:
    • api.chatRoom.setAuthenticationPattern(room, key, value, callback)
    • api.chatRoom.authorize(connection, room, callback)
    • api.chatRoom.reAuthenticate(connectionId, callback)
  • You can now overwrite the methods which save and return connection data to the chatroom data stores.
  • You can now also overwrite the method which builds/sanitizes the payload for all chat messages via updating api.chatRoom.generateMessagePayload(message)

Actions

You can finally provide defaults, validation, formatting, and requirements in an action's inputs.

This is a breaking change.

exports.sleepTest = {
  name: 'sleepTest',
  description: 'I will sleep and then return',

  inputs: {
    sleepDuration: {
      required: true,
      formatter: function(n){ return parseInt(n); },
      default: function(){ return 1000; }
      validator: function(n){
        if(n < 1000){ return 'sleepDuration should be longer than 1 second'; }
        else{ return true; }
      }
    }
  },

  run: function(api, connection, next){
     setTimeout(function(){
       next(connection, true);
    }, connection.params.sleepDuration)
  })
}

The options are:

  • required (boolean)
  • formatter = function(param, connection, actionTemplate)
    • will return the new value of the param
  • default = function(param, connection, actionTemplate)
    • will return the default value of the param
    • you can also have a static assignment for default father than a function, ie: default: 123
  • validator = function(param, connection, actionTemplate)
    • should return true if validation passed
    • should return an error message if validation fails which will be returned to the client
  • All the functions above are expected to be synchronous functions (no callbacks).
  • This removes separate sections within an action's definition for required and optional.
  • Minimally, if you just want to define a list of optional params, your action would look like this:
  • We no longer require an action to have inputs defined
  • We no longer require an action to have outputExample defined
  • The changed to the params was gone in https://github.com/evantahler/actionhero/pull/549 via @evantahler
  • You can now define api.config.general.missingParamChecks = [null, '', undefined] to choose explicitly how you want un-set params to be handled in your actions. For example, if you want to allow explicit null values in a JSON payload but not undifined, you can now opt-in to that behavior.

Tasks

  • MultiWorker
    • This moves actionhero's underlying task workers to be a single auto-scaling node-resque multiWorker, rather than many instances of node-resque workers.
    • From node-resque: node-resque provides a wrapper around the worker object which will auto-scale the number of resque workers. This will process more than one job at a time as long as there is idle CPU within the event loop. For example, if you have a slow job that sends email via SMTP (with low rendering overhead), we can process many jobs at a time, but if you have a math-heavy operation, we'll stick to 1. The multiWorker handles this by spawning more and more node-resque workers and managing the pool.
    • This changes (but simplifies) the configuration options for the task system to be:
exports.default = { 
  tasks: function(api){
    return {
      // Should this node run a scheduler to promote delayed tasks?
      scheduler: false,
      // what queues should the workers work?
      queues: ['*'],
      // how long to sleep between jobs / scheduler checks
      timeout: 5000,
      // at minimum, how many parallel taskProcessors should this node spawn?
      // (have number > 0 to enable, and < 1 to disable)
      minTaskProcessors: 0,
      // at maximum, how many parallel taskProcessors should this node spawn?
      maxTaskProcessors: 0,
      // how often should we check the event loop to spawn more workers?
      checkTimeout: 500,
      // how many ms would constitue an event loop delay to halt worker spawning?
      maxEventLoopDelay: 5,
      // When we kill off a taskProcessor, should we disconnect that local redis connection?
      toDisconnectProcessors: true,
      // What redis server should we connect to for tasks / delayed jobs?
      redis: api.config.redis
    }
  }
}

Websockets

  • Websocket client will now always check server for listing of rooms that the client is a member of with both roomAdd and roomLeave. This is required now that these methods can fail async.
  • You can now optionaly signal clients to disconnect or not when the server shuts down. Normally, you probably do not want this, as you would like the clients to reconnect on server deployment. This is a change from the previous behavior which would signal the the clients to not reconnect in earlier actionhero versions.
    • api.config.servers.websocket.destroyClientsOnShutdown = false controls this behavior.
  • 3 more WS client events have been added:

Severs

Config Directories

We support now multiple configuration paths as follows:

  1. Use the project 'config' folder, if it exists.
  2. "actionhero --config=PATH1 --config=PATH2 --config=PATH3,PATH4"
  3. "ACTIONHERO_CONFIG=PATH1,PATH2 npm start"

Note that if --config or ACTIONHERO_CONFIG are used, they overwrite the use of the default "config" folder. If you wish to use both, you need to re-specify "config", e.g. "--config=config,local-config". Also, note that specifying multiple --config options on the command line does exactly the same thing as using one parameter with comma separators, however the environment variable method only supports the comma-delimited syntax.

Via https://github.com/evantahler/actionhero/pull/541 by @crrobinson14

Generators & Project Layout

Misc

actionhero - v9.4.1: Fixes

Published by evantahler almost 10 years ago

Fixes

actionhero - v9.4.0: Lint And Domains

Published by evantahler almost 10 years ago

Code Coverage and Lint

Release v9.4.0 of actionhero is all about getting out code up-to-code! We spent the time to lint our js and integrate with test coverage tools

screen shot 2014-10-29 at 9 58 45 am

You can also now check out the actionhero project's coverage on codecliamte

In order to shape up, there are a few breaking changes:

Breaking Changes:

  • connection._original_connection becomes connection._originalConnection
  • callback of api.chatRoom.reAuthenticate now includes error as first argument, then the array of rooms that failed.
  • in the client-side js, the prototype actionheroClient becomes ActionheroClient, however, the old name is aliased for backwards compatibility.

Domains

actionhero has included domains for a while now. Domains allow you to wrap an entire request so that any uncaught errors can be handled (ie: return a 500 to the client, and not crash the application). This a good node defensive design pattern, but domains have some heavy overhead. Starting in this release, the use of domains is now optional, and configureable with api.config.general.actionDomains

Keep in mind that if you disable api.config.general.actionDomains, your application is likely to preform faster under load, but can be crashed by a single bad request. The choice is yours!

Misc

  • Thanks to @benburwell, we now have a button on the readme to launch a demo actionhero application directly to Heroku!
  • Bug Fixes
  • Dependent packages updated to the latest versions
actionhero - v9.3.2: Bugs and Route Params

Published by evantahler about 10 years ago

Routes

In this commit we have removed the 'auto-adding' of params from routes. Previously, if you listed a variable in a route (IE: /users/:userID) and you did not include userID as an input to your action, it would still have been possible to accept connection.params.userID in your action. Removing this feature makes actions safer and ensures that you truly only are getting the params you define into an action.

If you run into trouble with this update, be sure that your actions list all the params they expect!

See the conversation here for more details https://github.com/evantahler/actionhero/issues/481

Gitter

Added Gitter

Gitter is a chat tool based around github. I've made a gitter room for actionhero we can all chat in. This deprecates the old, rarely used IRC room. Gitter has mobile apps, desktop apps, and a good website with chat persistence. Like IRC, it is free.

Misc

We have updated all of actionhero's dependent packages to their latest versions (except for winston because of this issue)

This small release fixes a few bugs and docs:

  • Fix a bug in the redis initializer which would re-fire boot callbacks on re-connection and have wacky subscription behavior (thanks @jacobfike)
  • Fix a bug that wouldn't fully reload params from routes when in developer mode. (thanks @mstdokumaci)
  • Other little fixes
actionhero - v9.3.1: Default log level to INFO

Published by evantahler about 10 years ago

v9.3.1 is the very definition of a point release.

  • Having a default log level of DEBUG was annoying and scary.
actionhero - v9.3.0: Config Updates and Developer Help

Published by evantahler about 10 years ago

This release is packed full of updates aimed to make your job as an actionhero developer easier! A huge shout-out is due to @PhilWaldmann who completed the majority of the work in this release with 4 pull requests which added up to a substantial upgrade of the config system.

Config

Grunt (https://github.com/evantahler/actionhero/pull/449)

  • Cleanup the gruntfile, and load the gunt tasks from within the acitonhero project itself
  • Organize the grunt tasks into individual files
  • Update the new project generator to work with the above

Static Files

  • Allows the ability to define more than one path in api.config.general.paths.public.
  • This means you can serve static assets from more than one directory, including within a plugin.
  • Files will be searched for by the priority with the public root directories are defined.

Cache

  • Adding (optional) redis locks to the cache
  • You may optionally implement locking methods along with your cache objects. This will allow one actionhero server to obtain a lock on an object and prevent modification of it by another member of the cluster. For example you may want to first api.cache.lock a key, and then save it to prevent other nodes from modifying the object.

api.cache.lock

  • Invoke: api.cache.save(key, expireTimeMS, next)
    • expireTimeMS is optional, and will be expireTimeMS = api.cache.lockDuration = api.config.general.lockDuration
  • Callback: next(error, lockOk)
    • error will be null unless there was something wrong with the connection (perhaps a redis error)
    • lockOk will be true or false depending on if the lock was obtained.

api.cache.unlock

  • Invoke: api.cache.save(key, next)
  • Callback: next(error, lockOk)
    • error will be null unless there was something wrong with the connection (perhaps a redis error)
    • lockOk will be true or false depending on if the lock was removed.

api.cache.checkLock

  • Invoke: api.cache.save(key,retry, next)
    • retry is either null or an integer (ms) that we should keep retrying until the lock is free to be re-obtained
  • Callback: next(error, lockOk)
    • error will be null unless there was something wrong with the connection (perhaps a redis error)
    • lockOk will be true or false depending on if the lock is currently obtainable.

Misc

  • Update node-resque, redis, and primus to their latest versions
  • Fix a bug with the client-js which was generated via primus + engine.io.
actionhero - v9.2.2: errors and cookies

Published by evantahler about 10 years ago

This release is comprised of updates entirely from our growing actionhero community!

Error Objects ( @innerdvations )

  • fix the error reporter such that errors can be objects, especially when loaded from config/errors.js

Cookie Options ( @psc-bss )

actionhero - v9.2.1: Hotfix to allow nested routes

Published by evantahler about 10 years ago

This release is a hotfix to re-allow nested routes for api.config.servers.web.urlPathForActions and api.config.servers.web.urlPathForFiles. You can once again set them to /path/to/public

actionhero - v9.2.0: Error Reporting

Published by evantahler about 10 years ago

Error Reporter Updates

Updated the error reporter to provide more details to any api.exceptionHandlers.reporters. Reporters now will receive (err, type, name, objects, severity).

Documentation updates accordingly: http://actionherojs.com/docs/core/exceptions.html#custom-error-reporters

  • err is the error object (which you can extract err.stack from)
  • type is the type of method which crashed ('action', 'task', etc)
  • name will be a human-readable name, IE: action:randomNumber
  • objects is a hash which contains the relevant objects.
    • for an action, it will be {connection: connection}
    • for a task, it will be {task: task, queue: queue}
  • severity will be a logger severity level, like "error" or "alert".

Misc

  • Updated dependent packages
  • small fix to help with assigning response values for websocket clients
actionhero - v9.1.0: connection fingerprint and router updates

Published by evantahler about 10 years ago

To upgrade to this release, there are configuration changes required
This release also more harshly enforces some previously lax URL to Route matching. Your application behavior may change

Router Updates (https://github.com/evantahler/actionhero/pull/433)

  • simple routing
    • to clear up actionhero's simple routing (/api/:action), this logic is now moved into the router
    • simple routing can be disabled via api.config.servers.web.simpleRouting
  • query routing
    • to clear up actionhero's query routing (/?action=:action), this logic is now optional via api.config.servers.web.queryRouting
  • all parts of a url must match for a route to be activated and the same depth will be enforced
    • IE: /api/thing/stuff matches {path: '/thing/:value', action: 'myAction'} but will not match {path: '/thing', action: 'myOtherAction'}
  • you can no longer request a file with a query param, ie: /public?file=simple.html. The URL path must math the file system path (from /public)
  • when the action provided by a user is not found, we will simply return the error 'unknown action or invalid apiVersion'
    • the action will not be assumed via the URL

Connection Fingerprint (https://github.com/evantahler/actionhero/pull/436)

  • promote fingerprint to be a top-level connection element (connection.fingerprint)
    • previously connection.rawConnection.fingerprint
  • add connection.fingerprint to websocket connections whenever possible via api.config.servers.web.fingerprint.cookieKey
  • this is impossible to test without a real browser, so /public/linkedSession.html is provided to demonstrate
  • Thank you @S3bb1 and @englercj for your help with this one
  • relevant documentation changes https://github.com/evantahler/actionhero/pull/437

screen shot 2014-07-26 at 3 20 34 pm

Backwards Incompatibility

  • There are 2 new options in /config/servers/web.js
    • simpleRouting
    • queryRouting
  • api.config.servers.web.returnErrorCodes now defaults to true

Documentation

Misc

  • serving static files can be disabled for the web server by setting api.config.servers.web.urlPathForFiles = null
  • serving static files can be disabled all together by setting api.config.general.paths = null
  • optionally allow for setKeepAlive on socket clients (https://github.com/evantahler/actionhero/pull/420)
  • router will no longer crash when parsing a malformed url, IE: site.com/%/thing (note that % was not htmlEncoded)
actionhero - v9.0.3: Redis Auth Fix

Published by evantahler over 10 years ago

A fix for the way we connect to redis with authentication.

actionhero - v9.0.2: Websocket Updates

Published by evantahler over 10 years ago

Websocket Client Updates

screen shot 2014-07-01 at 9 14 53 pm

  • Added websocket load test to project. How fast are your servers?
  • Use the in-browser implementation for EventEmitter provided by Primus rather than rolling our own
  • Fix apiPath options for HTTP fallback in actionheroClient

Misc

  • Better missing variable detection in actionProcessor (thanks @joezg)
  • redis client options update (thanks @panva)
  • Typos (thanks @smolations)
actionhero - v9.0.1: Bug Fixes

Published by evantahler over 10 years ago

This release is a collection of bug fixes:

Bug Fixes:

actionhero - v9.0.0: Chat Re-Write, Performance, and Developer Tools

Published by evantahler over 10 years ago

v9.0.0

This release focuses on performance, the chat system, and developer tools. We have been listening to your thoughts in the mailing list and on GitHub, and hopefully this release clears up a lot of the confusion and pain points you have identified!

Chat Re-Write

In v9.0.0, the chat system has been gutted and re-written to provide your API with finer controls about chat rooms. Most importantly, you can now control which rooms connections are members of directly. Connections can continue opt to join and leave rooms on their own (assuming the authenticationPattern is met).

  • No more "listening" to rooms; Clients can be in more than one room at a time
    • Clients can no longer "listen" or "silence" to rooms. You are either in a room or not.. but now you can be present in more than one room!
      • This is a change to the socket and websocket servers, the base connection object, and the client-facing JS library.
    • say now require a room name, IE: say myRoom Hello World over telnet and the socket server, or client.say(room, message, callback) in the websocket client
    • There are updates to the browser-facing actionHeroClient.js (and .min) to reflect these changes
    • The Client APIs for joining and leaving rooms is simplified simply to roomAdd room and roomLeave room
  • When you set the authentication rules for a room, all clients already in that room will be re-checked and kicked out if needed
  • New methods for server-side control of rooms:
    • api.chatRoom.add(room, callback)
    • api.chatRoom.destroy(room, callback)
      • now connections will be notified of a room closing and be removed
    • api.chatRoom.exists(room, callback)
    • api.chatRoom.setAuthenticationPattern(room, key, value, callback)
      • as noted above, connections already in the room will be re-checked
    • api.chatRoom.roomStatus(room, callback)
    • api.chatRoom.authorize(connection, room, callback)
      • test if a connection would be allowed to enter a room
    • api.chatRoom.reAuthenticate(connectionId, callback)
      • check all a connection's rooms, and remove any that aren't currently authorized
    • api.chatRoom.addMember(connectionId, room, callback)
      • you can add a member by ID to your room
    • api.chatRoom.removeMember(connectionId, room, callback)
      • you can remove a member by ID to your room

Primus

In this release, we have removed our dependency on faye in favor of Primus. We now use Primus in the websocket transport, and have moved all backend cluster-cluster communication to raw redis Pub/Sub.

The Primus project allows you to choose from many webscoket backends, including ws, engine.io, socket.io, and more. A number of new options have been added to /config/servers/websocket.js to manage this. Check out the Primus project for more information.

WARNING

actionhero will no longer attempt to manage non-sticky client connections. This means if you have a multi-server actionhero deployment and you use long-polling in your websocket transport, you will need to ensure that your load balancer can enforce sticky connections, meaning every request from the client will hit the same actionhero node.

Implementation Notes
  • There should be no functional changes to the Browser-facing actionheroClient.js, meaning the methods should all behave the same. However, there have been significant changes under the hood.
  • The Faye initializer has been removed.
  • in new actionhero projects, we will include the ws package as the backend for Primius (so we can generate a working project), but you do not need to keep this package.
  • actionhero generate will no longer create the client-facing actionheroClient.js on generation. Rather, the server will re-generate these files on boot each time. This is done so you can make changes in /config/servers/webscoket.js and have them included into the client JS. 3 new config options help mange the creation of these files:
// you can pass a FQDN here, or function to be called / window object to be inspected
clientUrl:        'window.location.origin',
// Directory to render client-side JS.  
// Path should start with "/" and will be built starting from api.config..general.paths.public
clientJsPath:     'javascript/',
// the name of the client-side JS file to render.  Both `.js` and `.min.js` versions will be created
// do not include the file exension
// set to `null` to not render the client-side JS on boot
clientJsName:     'actionheroClient',

RPC

To enable the new chat API above, a key feature was the ability to add connections to a room using "serverA"'a API, even though the connection in question might not be connected to "serverB". This required the creation of a robust Remote Procedure Call (RPC) to allow actionhero servers to communicate with each other.

You can call an RPC to be called on all nodes you may have in your cluster or just a node which holds a specific connection. You can call RPC methods with the new api.redis.doCluster method. If you provide the optional callback, you will get the first response back (or a timeout error). RPC calls are invoked with api.redis.doCluster(method, args, connectionId, callback).

For example, if you wanted all nodes to log a message, you would do: api.redis.doCluster('api.log', ["hello from " + api.id]);

If you wanted the node which holds connection abc123 to change their authorized status (perhaps because your room authentication relies on this), you would do:

api.connections.apply('abc123', 'set', ['auth', true], function(err){
  // do stuff
});

Two new options have been added to the config/redis.js config file to support this:

// Which channel to use on redis pub/sub for RPC communication
channel: 'actionhero',
// How long to wait for an RPC call before considering it a failure 
rpcTimeout: 5000, 

WARNING

RPC calls are authenticated against api.config.serverToken and communication happens over redis Pub/Sub. BE CAREFUL, as you can call any method within the API namespace on an actionhero server, including shutdown() and read any data on that node.

Connections

The new api.connections.apply(connectionId, method, args, callback) has been introduced. This allows any node in the cluster to modify a property of a connection, even one that isn't located locally on this specific node. This uses the RPC tooling described above under the hood.

Web Server Updates

  • actionhero's web server can now accept the PATCH HTTP verb (thanks @omichowdhury). This verb can also now be used in routes.
  • actionhero's web server will now allow you to access the raw form variables (un sanitized by the actionProcessor). connection.rawConnection.params.body and connection.rawConnection.params.files are available within middleware and actions (Thanks @omichowdhury)
  • adding a callback param will only convert the response to JSONp (application/javascript) if the header would have still been x/json
  • if the header isn't application/json or application/javascript, the server will no longer attempt to JSON.stringify the connection.response.
    • This means you can manually create XML, Plain Text, etc responses as long as you also change the mime (IE: connection.rawConnection.responseHeaders.push(['Content-Type', 'text/plain']);) (thanks @enginespot)
  • internally traded connectionHasHeader() for extractHeader() which will return the most recent header of a given name

Middleware Priorities

Thanks to @innerdvations, you can now choose how to order the execution of your middleware (preProcessor and postProcessor, and connection callbacks). You should no longer push to those arrays (although your application won't error). You should now use api.actions.addPreProcessor(function, priority) and api.actions.addPostProcessor(function, priority) for actions and api.connections.addCreateCallback(function, priority) and api.connections.addDestroyCallback(function, priority) for connections.

The priority in all the above is optional, and if not provided, the new api.config.general.defaultProcessorPriority will be used (defaults to 100).

Room Middleware

Per a discussion on the mailing list, we have removed any automatic messaging actionhero might do for the chatrooms in favor of another type of middleware, chat middleware! This middleware allows you to control the messages and actions taken when clients join or leave a chat room.

This should not be used for authentication.

As we do not want to block the ability for a connection to join a room (we already have authentication tools in place), Chat Middleware does not have a callback and is executed "in parallel" to the connection actually joining the room. This middleware can be used for announcing members joining and leaving to other members in the chat room or logging stats.

Use api.chatRoom.addJoinCallback(function(connection, room)) to add a Join Callback, and use api.chatRoom.addLeaveCallback(function(connection, room) to handle connections leaving a room.

You can optionally provide a priority to control the order of operations in the middleware.

You can announce to everyone else in the room when a connection joins and leaves:

api.chatRoom.addJoinCallback(function(connection, room){
  api.chatRoom.broadcast(connection, room, 'I have entered the room');
});

api.chatRoom.addLeaveCallback(function(connection, room){
  api.chatRoom.broadcast(connection, room, 'I have left the room');
});

REPL

actionhero now has a REPL! This means you can 'connect' to a running instance of actionhero and manually call all the methods on the api namespace. This combined with the new RPC tools make this a powerful debugging and development tool. Running grunt console will load up a version of action hero in your terminal where you have access to the api object. This version of the server will boot, initialize, and start, but will skip booting any servers.

The REPL will:

  • source NODE_ENV properly to load the config
  • will connect to redis, and load any user-defined initializers
  • will load any plugins
  • will not boot any servers

If you are familiar with rails, this is very similar to rails console

Variable Error Message

Many of you have asked for the ability to change the string error messages actionhero uses. Perhaps english isn't your user's language, or you want so say something custom. Either way, there's a new config file just for this: config/errors.js. Each error message is represented by a synchronous function which should return a string. Some functions are passed variables (like the connection) so you can customize your message.

Performance

Over the past few months, a great conversation has been happening on GitHub about actionhero speed & performance. This conversation has lead to a few small tweaks inside actionhero which have made a big difference. Most importantly, somewhere between v7.0.0. and v8.0.2 we changed the async-ness of the actionProcessor and cache system to rely on setImmediate rather than process.nextTick. This change made the seder less susceptible to crashing under heavy load, but cost us significantly in speed. This change was too costly and has since been reverted.

Thank you to everyone who contributed to the conversation!

The change to Priums not only allows for more flexibility in the websocket server, but in preliminary tests, preforms much better than faye.

Breaking Changes

A list of things to watch out for when upgrading to v9.0.0 form v8.x.x:

  • actionhero now requires node > v0.10.0
  • The browser-facing JS (actionHeroClient) has been updated. You are required to use the new JS in v9.0.0 projects
  • Actionhero now requires a load balancer with sticky connections to use websockets + long polling. Actionhero will no longer support websocket long polling + the node cluster module. "real" websockets + the node cluste rmodule will continue to work.
  • The Redis config file /config/redis.js has new options. These new options are required for the RPC system.
  • We have removed /config/faye.js
  • For the updates to middleware order processing, a new config variable has been added to /config/api.js, defaultProcessorPriority : 100,
  • For the new error strings, thew new /config/errors.js is required.
  • A number of new options have been added to /config/servers/websocket.js to manage this. Check out the Primus project for more information.

Misc

  • api.utils.hashMerge/ api.utils.isPlainObject have been updated to check provided hashes (or nested hashes) for a special key, _toExpand. If this key is false, this object will not be expanded on merge, and copied over literally.
  • the actionProcessor will now also append connection.actionStatus if a connection processes an action
    • actionStatus can be an error string, like 'missing_params', null, true, or false
      • a status of true mean the action ran, but there still may be a connection.error
      • this status is mostly used for setting HTTP error codes in the web server
  • Many new tests added for chat and RPC
  • Test cleanup overall for servers
  • Various small bug fixes and improvements
  • Various dependent packs updated to their latest versions
    • This includes updating node-resque to v0.8.0, which allows errors to be caught and suppressed via plugin