Actionhero is a realtime multi-transport nodejs API Server with integrated cluster capabilities and delayed tasks
APACHE-2.0 License
Bot releases are hidden (Show)
Published by evantahler over 8 years ago
Published by evantahler over 8 years ago
We now have an actionhero code style guide! When working on Actionhero, be sure that your IDE/Editor has support for eslint. We also now have contribution guides for the project: https://github.com/evantahler/actionhero/blob/master/CONTRIBUTING.md. I don't get the Lavendarman
reference, but the file is full of good advice anyway!
Fixed a bug which prevented static files with spaces in their names from being sent to clients
Oh windows... why did you have to do everything differently than every other operating system? Even your path delimiters (\
vs /
) go the wrong way. Anyway... the Actionhero test suite now runs on windows!
Fixed a bug which would report and log actionhero worker names with repeat IDs when running startCluster
with a worker count above 10.
NODE_ENV
vs developmentMode
Published by evantahler over 8 years ago
shutdownTimeout
is reached because actionhero couldn't stop in time, we now throw an error rather than just simply process.exit(1)
. This will present the error to stdout properly and be caught as an uncaughtError
by actionhero startCluster
to be logged.
api.cache.pop
, if there are no results, always return undefined
(some redis adaptors would return null)
Published by evantahler over 8 years ago
From node resque: https://github.com/taskrabbit/node-resque/pull/121
This is a (potentially) breaking change
When comparing this project to ruby resque, we had been using the wrong value (key pointer) in the delayed job queue. When running this project alongside a ruby scheduler, it was possible for older timestamp key set entries not to be deleted. This update corrects the difference.
When upgrading to this new version, it is very likely you will end up with queue artifacts that are not properly deleted, which have the potential to break plugin's behaviors. This will require manual intervention to remove keys that match resque:timestamps:*
. Before upgrading to this version, the safest path forward is to drain all of your queues and schedules first, using the previous version of node-resque.
As far as actionhero is concerned, this issue would only effect you if your application uses scheduler and api.tasks.enqueueAt
or api.tasks.enqueueIn
directly. This is why we have made this a minor version update.
Published by evantahler over 8 years ago
Published by evantahler over 8 years ago
by @evantahler via https://github.com/evantahler/actionhero/pull/779
api.cache
implements a distributed shared list. 3 simple functions are provided to interact with this list, push
, pop
, and listLength
. These lists are stored in Redis, and cannot be locked. That said, a push
and pop
operation will guarantee that one-and-only-one copy of your data is returned to whichever application acted first (when popping) or an error will be returned (when pushing).
api.cache.push(key, data, next)
next(error)
api.cache.pop(key, next)
next(error, data)
api.cache.listLength(key, next)
next(error, length)
0
will be returnedstartingChatRooms
so new projects don't have to override this setting [https://github.com/evantahler/actionhero/commit/692fde7cb388bf3d0edb05d9defd8ec8fae9b55d]Published by evantahler over 8 years ago
The previous release had an error in the syntax of a warning message which would crash on on some operating systems.
https://github.com/evantahler/actionhero/commit/bca3b002e5922bb84a8b56a4751d267d66092ee2
Published by evantahler over 8 years ago
With some redis libraries (identified in ioredis), when using sentinels to connect to redis, it was possible to have an Unhandled rejection
error. This update changes the order in which subscriptions happen in relation to the connection callback.
Published by evantahler over 8 years ago
When running actionhero startCluster
, we we will now detect is the workers/servers under the cluster are rapidly crashing with either an uncaughtException
or unhandledRejection
. By default, we will check every 30 seconds for this, and if the number of these errors is greater than 2x expected number of workers (set with the --workers
flag), the cluster will exit.
Published by evantahler over 8 years ago
[HOTFIX] - When linking plugins with public directories, their /public
directories should be sourced by the static file server.
We should not modify api.config.general.paths.public
to do this.
Published by evantahler over 8 years ago
Fixes a bug in which actionhero startCluster
would fail if the log directory was a symlink
Published by evantahler over 8 years ago
v13.0.0
A number of changes (below) have updated the capabilities of the actionhero binary. The new list (and help.txt) is:
actionhero - A multi-transport node.js API Server with integrated cluster capabilities and delayed tasks
Binary options:
* help (default)
* start
* startCluster
* generate
* generateAction
* generateTask
* generateInitializer
* generateServer
* actions
* enqueueTask
* console
* link
Descriptions:
* actionhero help
will display this document
* actionhero start --config=[/path/to/config.js] --title=[processTitle] --daemon
will start a template actionhero server
this is the respondent to "npm start"
[config] (optional) path to config.js, defaults to "process.cwd() + '/' + config.js". You can also use ENV[ACTIONHERO_CONFIG].
[title] (optional) process title to use for actionhero-s ID, ps, log, and pidFile defaults. Must be unique for each member of the cluster. You can also use ENV[ACTIONHERO_TITLE]. Process renaming does not work on OSX/Windows
[daemon] (optional) to fork and run as a new background process defaults to false
* actionhero startCluster --workers=[numWorkers] --daemon
will launch a actionhero cluster (using node-s cluster module)
[workers] (optional) number of workers (defaults to # CPUs - 2)
[daemon] (optional) to fork and run as a new background process defaults to false
* actionhero generate
will prepare an empty directory with a template actionhero project
* actionhero generateAction --name=[name] --description=[description] --inputsRequired=[inputsRequired] --inputsOptional=[inputsOptional]
will generate a new action in "actions"
[name] (required)
[description] (required) should be wrapped in quotes if it contains spaces
* actionhero generateTask --name=[name] --description=[description] --scope=[scope] --frequency=[frequency]
will generate a new task in "tasks"
[name] (required)
[description] (required) should be wrapped in quotes if it contains spaces
[scope] (optional) can be "any" or "all"
[frequency] (optional)
* actionhero generateInitializer --name=[name]
will generate a new initializer in "initializers"
[name] (required)
* actionhero generateServer --name=[name]
will generate a new server in "servers"
[name] (required)
* actionhero actions
will list all actions in this server to stdout
* actionhero enqueueTask --name=[taskName] --args=[JSON-formatted args]
will enqueue a task into redis
* actionhero console
will open an interactive CLI with the API object in scope.
this is sometimes called a REPL
* actionhero link --name=[pluginName]
will link the actions, tasks, initializers, etc from a plugin into your top-level project
normally, you will have first installed the plugin via `npm install myPlugin`
#############################################################
## More Help & the actionhero documentation can be found @ ##
## http://www.actionherojs.com ##
#############################################################
(by @evantahler via https://github.com/evantahler/actionhero/pull/756)
This allows localization of responses to connections and the api server logs using the i18n node module.
api.config.i18n.updateFiles = true
, you will see actionhero generate a 'locales' folder at the top level of your project which will contain translations of all strings in your project with are passed though the new localization system. This includes all uses of connection.localize
and api.log
.
api.config.i18n.updateFiles
if you do not want this behavior.Since every actionhero implementation is unique, we cannot ship with a "guess" about how to determine a given connection's locale. Perhaps you have an HTTP server and you can trust your client's accept-language
headers. Or perhaps you run your API under a number of different host names and you can presume locale based on them. Whatever the case, you need to create a synchronous method in an initializer which will be called when each connection connects to return its locale.
For example, I may have an initializer in my project like this:
module.exports = {
initialize: function(api, next){
api.customLocalization = {
lookup: function(connection){
var locale = 'en';
if(connection.type === 'web'){
if(connection.rawConnection.req.headers.host === 'usa.site.com'){ locale = 'en-US'; }
if(connection.rawConnection.req.headers.host === 'uk.site.com'){ locale = 'en-GB'; }
if(connection.rawConnection.req.headers.host === 'es.site.com'){ locale = 'es-ES'; }
if(connection.rawConnection.req.headers.host === 'mx.site.com'){ locale = 'es-MX'; }
}
return locale;
}
}
next();
}
}
To tell the i18n to use this method with a new connection, set api.config.i18n.determineConnectionLocale = 'api.customLocalization.lookup'
config/errors.js
has been completely redone to take advantage of connection.localize
config/i18n
:exports.default = {
i18n: function(api){
return {
// visit https://github.com/mashpie/i18n-node to see all configuration options
// locale path can be configired from within ./config/api.js
locales: ['en'],
fallbacks: {
'en-US': 'en',
},
updateFiles: true,
// this will configure logging and error messages in the log(s)
defaultLocale: 'en',
// the name of the method by which to determine the connection's locale
// by default, every request will be in the 'en' locale
// this method will be called witin the localiazation middleware on all requests
determineConnectionLocale: 'api.i18n.determineConnectionLocale',
}
}
};
exports.procution ={
i18n: function(api){
return {
updateFiles: false
}
}
}
connection.localize(string)
or connection.localize([string-with-interpolation, value])
data.response.message = connection.localize('the count was %s', 4);
In your locale files, you would define the count was %s
in every language you cared about, and not need to modify the action itself at all.api.log()
api.log(['The time is %s', new Date()], 'alert')
.The time is %s
in your locale files would apply to the logger as well!actionhero link --name=name_of_plugin
When running actionhero link --name=name_of_plugin
, we look though your api.config.general.paths.plugin
(which contains ./node_modules
by default) for the named plugin. If we find it, we link
in the actions, initializers, tasks, and servers found there. These files will then be "present" in your project via that linkfile. A linkfile is a simple file with the name of {pluginName}.link
in the top level folder of that type of thing (like actions or tasks)
For example, if you install myPlugin
via npm install --save myPlugin
into your project's ./node_modules
folder, and then npm run actionhero link --name myPlugin
, this will work perfectly.
Files found in the /config
directory of the plugin will be copied into your project's top level config
directory. This is under the assumption that you will want to modify these settings. Config files within a plugin itself will not get sourced.
A previous version of this tool used OS symlinks, but that was removed to enable cross-platform compatibility.
The good news is that we can count on NPM to properly (relatively) install any dependent plugins as a child in their local node_modules
, so it shouldn't be too hard.
/config
will get automatically copied into the user's project when they run actionhero link
. Make sure that you have some good comments!path.sep
for file path separators and things like that. Use relative paths for everything in your plugin.actions
, enqueueTask
, and console
to the actionhero binaryapi
set as this
.api
object within input operations like formatter
and validator
this
is set to the api
object within these sync methodsstartCluster
module has been re-written to improve speed, stability, and legibilitySIGHUP
has been fixed to wait on each worker to fully return before moving on to restart the next one (with a timeout)HEAD
http verb is allowed in the router
eval
via dynamic method invocation
object.package
is a reserved word. Updated. how redis/resque handles it's underlying connection to be renamed to pkg
.Published by evantahler almost 9 years ago
This change renames the variable package
in redis config to pkg
. package
is a reserved word in javascript and should not have been used.
The package node-resque
, which actionhero relies on, has also updated this configuration setting.
Published by evantahler almost 9 years ago
4.0.0
.Many of the packages we depend on are moving to target the LTS release of 4.2.2
as their minimum build. Actionhero will be following suit. Version 13.0.0 will have a target of node >=4.0.0
matchTrailingPathParts
in routerEnables a new option, matchTrailingPathParts
which you can enable in the router to match combination paths:
post: [
// yes match: site.com/api/123
// no match: site.com/api/123/admin
{ path: '/login/:userId(/.*/)', action: 'login' }
],
post: [
// yes match: site.com/api/123
// yes match: site.com/api/123/admin
{ path: '/login/:userId(/.*/)', action: 'login', matchTrailingPathParts: true }
],
This also enables "catch all" routes, like:
get: [
{ path: ':path(/.*/)', action: 'catchAll', matchTrailingPathParts: true }
],
If you have a route with multiple variables defined and matchTrailingPathParts
is true, only the final segment will match the trailing sections:
get: [
// the route site.com/users/123/should/do/a/thing would become {userId: 123, path: '/should/do/a/thing'}
{ path: '/users/:userId/:path(/.*/)', action: 'catchAll', matchTrailingPathParts: true }
],
by @evantahler via https://github.com/evantahler/actionhero/pull/728
Published by evantahler almost 9 years ago
There were a number of old methods within the api.utils
namespace which we are not using. Some of them were actually quite dangerous. They are gone now.
api.utils.sqlDateTime(time)
api.utils.sqlDate(time)
api.utils.randomString(chars)
api.utils.sleepSync(seconds)
api.utils.randomArraySort(arr)
api.utils.inArray(haystack, needle)
workerLogging : {
failure : 'error', // task failure
success : 'info', // task success
start : 'info',
end : 'info',
cleaning_worker : 'info',
poll : 'debug',
job : 'debug',
pause : 'debug',
internalError : 'error',
multiWorkerAction : 'debug'
},
// Logging levels of the task scheduler
schedulerLogging : {
start : 'info',
end : 'info',
poll : 'debug',
enqueue : 'debug',
reEnqueue : 'debug',
working_timestamp : 'debug',
transferred_job : 'debug'
},
server
or worker
modePublished by evantahler almost 9 years ago
QS
to enable array and complex param parsing for the web server[qs](https://github.com/hapijs/qs)
package (originally from TJ Holowaychuk, and now maintained by the Hapi.JS team) is an excellent query-string parsing library made to expand upon and replace node's built-in url.parse
. It handles more esoteric cases like merging ?collection[]=first&collection[]=second
into an array containing both 'first'
and 'second'
. More importantly, It allows you to configure how to handle special cases of posting object, deeply nested params, etc.api.config.servers.queryParseOptions
, which will be passed to the qs
parser.trace
log level, which is a reversion of https://github.com/evantahler/actionhero/pull/595, which we added in February of this year. This means that if you run your actionhero server with the log level of debug
, you will now see messages which had been previously tagged as trace
.
api.config.logger.levels
and api.config.logger.colors
. See Winston's documenation for more information. This will allow you do bring back trace
and other custom log levels for your actions/initializers.Published by evantahler almost 9 years ago
web
server to fix a memory leak (introduced via https://github.com/evantahler/actionhero/pull/689) which caused connections to be destroyed (and stay in RAM) on some operating systems + node versions.Oh, and we have a new documentation website! Check out http://www.actionherojs.com/docs
Published by evantahler almost 9 years ago
The previous version of actionhero (v12.2.1) has been pulled from NPM and replaced with this version.
A dependent package, [email protected]
was pulled from NPM. This package relaxes the requirement.
Published by evantahler almost 9 years ago
Published by evantahler almost 9 years ago
if-modified-since
headers when serving static files304
header if there is no change. Save bandwidth!configChanges
early so that if you are overriding plugin directories, it will take (https://github.com/evantahler/actionhero/commit/7a082ee25a1852a01eb843b91cfae30febd5496a)