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 visible (Hide)

actionhero - v21.0.15

Published by evantahler over 4 years ago

actionhero - v21.0.14

Published by evantahler over 4 years ago

  • Update dependancies
  • JSON-stringify plugin options when logging the plugin which caused a task/resque re-Enqueue event
actionhero - v21.0.13

Published by evantahler over 4 years ago

actionhero - v21.0.11

Published by evantahler almost 5 years ago

Update type of pluginOptions to hash

actionhero - v21.0.10

Published by evantahler almost 5 years ago

Filter and include task arguments in task log messages (https://github.com/actionhero/actionhero/pull/1391)

Before

info: [ worker ] job success workerId=1 class=hello queue=default

After

info: [ worker ] job success workerId=1 class=hello queue=default args={"thing":"[FILTERED]", "id": 123}

We use config.general.filteredParams, like the web server, to decide what params to filter when logged.

Misc

actionhero - Typescript

Published by evantahler almost 5 years ago

Why Typescript?

Actionhero has moved to Typescript.

Typescript is a language that compiles to javascript that makes the developer experience much nicer. It includes features like type checking, sharing interfaces and modules, and generally other "quality of life" features found in other languages to help you write better javascript code.

For Actionhero, that means we can now provide:

Type Hinting

Module definitions

Automatic Documentation directly from the code

Visit docs.actionherojs.com to see this live!

...and an overall more pleasant developer experience!

Note: You do not have to use Typescript to use Actionhero! Other than some layout changes to your project, you can continue to use Actionhero with regular javascript node.js projects. We will always ship compiled javascript files to NPM so that actionhero will still work with the most recent versions of Node.js. That said, the generators will favor Typescript projects moving forward, creating Typescript files

For now, the latest Actionhero tag on NPM is still v20, the last javascript version of Actionhero. You can start using the Typescript version of Actionhero today by opting into the next tag:

npm install actionhero@next
./node_modules/.bin/actionhero generate
npm install
npm run dev

Actionhero will create and install everything you need for a pleasant typescript experience, including a tsconfig file, node's @types and development tools already linked into your package.json


Upgrading Packages & Package.json

If you are upgarding an existing Actionhero project, the first thing to do is install the related packages and create new files:

npm install --save actionhero@next
npm install --save-dev @types/node prettier
npm uninstall standard

Update your scripts in package.json

"scripts": {
  "dev": "ts-node-dev --transpile-only ./node_modules/.bin/actionhero start",
  "start": "actionhero start",
  "actionhero": "actionhero",
  "test": "jest",
  "pretest": "npm run build && npm run lint",
  "postinstall": "npm run build",
  "build": "tsc --declaration",
  "lint": "prettier --check src/*/** __test__/*/**",
  "pretty": "prettier --write src/*/** __test__/*/**"
},

and your jest config as well, also in package.json

"jest": {
  "testEnvironment": "node",
  "transform": {
    "^.+\\.ts?$": "ts-jest"
  }
};

Remove the block about standard from your package.json. We are switching to prettier because it has better typescript support.

Remember - you will be using npm run dev now when developing locally.

Typescript Configuration

Typescript is managed by a tsconfig.json file at the root of your project. Create one now with the following content:

{
  "compilerOptions": {
    "outDir": "./dist",
    "allowJs": true,
    "module": "commonjs",
    "target": "es2018"
  },
  "include": ["./src/**/*"]
}

Project Structure

  1. Create the src and dist directories
  2. Move Actions, Tasks, Initializers, Servers, and Config into src
  3. Create a new modules directory

Your project should now look like this:

|
|- boot.js
|- src
|  - config
|    - (project settings)
|
|  - actions
|    -- (your actions)
|
|  - initializers
|    -- (any additional initializers you want)
|
|  - servers
|    -- (custom servers you may make)
|
|  - tasks
|    -- (your tasks)
|
|  - bin
|    -- (your custom CLI commands)
|
|- locales
|-- (translation files)
|
|- __tests__
|-- (tests for your API)
|
| - log
|-- (default location for logs)
|
|- node_modules
|-- (your modules, actionhero should be npm installed in here)
|
|- pids
|-- (pidfiles for your running servers)
|
|- public
|-- (your static assets to be served by /file)
|
readme.md
package.json

Update JS to TS syntax

Typescript uses the latest ES6-style syntax for importing and exporting things. You do not need to use babel to get this to work... Typescript does it for you!

  • Rename all the files you just moved into src from *.js to *.ts files
    • A Helpful rename command for unix/osx computers to do this is -> for f in _.js; do mv -- "$f" "${f%.js}.ts"; done
  • Change the imports from Require-style const {thing} = require('thing') to Import-style import { thing } from 'thing'
  • Change all the exports from Module-style module.exports = ... or exports.thing = ... to ES6-style export const thing = ...

For example:

OLD

const { Action } = require("actionhero");

exports.default = class MyAction extends Action {
  constructor() {
    super();
    this.name = "hello";
    this.description = "an actionhero action";
    this.outputExample = { message: "hello" };
  }

  async run({ response }) {
    response.message = "hello";
  }
};

NEW

import { Action } from "actionhero";

export class MyAction extends Action {
  constructor() {
    super();
    this.name = "hello";
    this.description = "an actionhero action";
    this.outputExample = { message: "hello" };
  }

  async run({ response }) {
    response.message = "hello";
  }
}

Config

The config module (it is a module now!) produces a static object with your configuration. This means that it can be required via import {config} from 'actionhero' at any point in your project's life cycle... you no longer need to wait for the initialization process to complete. However, this required some changes:

  • The config methods no longer provide api, they provide config. Only other information from other config files is available to you, nothing from the rest of the application.

To upgrade your config:

  • Change all of the exports, per above. When exporting the default config, use DEFAULT (all caps), ie: export const DEFAULT = {config: { ... }}
  • Update your paths in config/general , ie:
paths: {
  action: [path.join(__dirname, "..", "actions")],
  task: [path.join(__dirname, "..", "tasks")],
  server: [path.join(__dirname, "..", "servers")],
  cli: [path.join(__dirname, "..", "bin")],
  initializer: [path.join(__dirname, "..", "initializers")],
  public: [path.join(process.cwd(), "public")],
  pid: [path.join(process.cwd(), "pids")],
  log: [path.join(process.cwd(), "log")],
  plugin: [path.join(process.cwd(), "node_modules")],
  locale: [path.join(process.cwd(), "locales")],
  test: [path.join(process.cwd(), "__tests__")],
  src: path.join(process.cwd(), "src"),
  dist: path.join(process.cwd(), "dist")
}

Don’t forget any paths you might have in other environments (like test)!

Middleware and Sessions

Now with Typescript, you’ll get an error if you try to set arbitrary properties on the data object either within an Action or Middleware. We need a place to pass data from the middleware to the action.

// in an initializer
import { action } from "actionhero";
import { models } from "./../models"; // in your project

const authenticatedTeamMemberMiddleware = {
  name: "authenticated-team-member",
  global: false,
  priority: 1000,
  preProcessor: async data => {
    const { Team, TeamMember } = models;
    const sessionData = await api.session.load(data.connection);
    if (!sessionData) {
      throw new Error("Please log in to continue");
    } else if (
      !data.params.csrfToken ||
      data.params.csrfToken !== sessionData.csrfToken
    ) {
      throw new Error("CSRF error");
    } else {
      const teamMember = await TeamMember.findOne({
        where: { guid: sessionData.guid },
        include: Team
      });
      data.session.data = sessionData; /// <--- HERE/
      data.session.teamMember = teamMember; /// <--- HERE/
    }
  }
};

action.addMiddleware(authenticatedTeamMemberMiddleware);

Modules and Initializers

A number of things have been moved out of the API object to simplify their use by creating import/export modules you can require directly. In this way, you can get type hinting for various parts of Actionhero! This is a logical separation between initializers - code that executes when your server boots up and loads or connects vs modules which provide an API for you to use in your code.

For example, the task system has been split into 2 parts - both a module and initializer. The initializer continues to load your tasks into api.tasks.tasks, but doesn’t expose any methods for you to use. Now, when you want to enqueue a task, you call task.enqueue() you load it from the module via import {task} from 'actionhero'

The initialize, start, and stop methods of your initializers will now be passed config. This is helpful in the off chance you are modifying config and cannot rely on the static export of that information (this is rare).

Removed from the API object and are now directly exported by Actionhero as modules:

ie: import { log, config } from 'actionhero'

  • log (the method to write to the logs)
  • config (the config object hash)
  • action (addMiddleware)
  • task (addMiddleware)
  • cache
  • task
  • i18n
  • specHelper
  • id (the server’s id)
  • env (development, staging, production)
  • localize (method that accepts a string and a connection)

The API object

what remains on the API object are truly things about your API - actions, tasks, servers, initializers. And now these elements are very typesafe. You can no longer add and remove things randomly to the API object. This means that in your project, you should create imports and exports directly and share them with your actions and tasks.

Polyfill

A polyfill will be included in the first few releases of Actionhero in typescript to port the new exports back to the api object. A warning will be displayed.

A new config setting to enable or disable the polyfill is located at config.general.legacyApiPolyfill

Config

  • config.general.id: can no longer be set
  • config.i18n.determineConnectionLocale: this method should be set on the i18n object exported by Actionhero.

Chat

  • chatRoom.sanitizeMemberDetails() is no longer overrideable/customizable.

WatchFileAndAct

We have removed the custom module loaders for Actionhero's development mode, watchFileAndAct. Now that we need to transpile our applications from typescript to javascript, we can rely on some of the excellent packages already developed for this purpose. Newly generated Actionhero projects will make use of node-ts-dev (https://github.com/whitecolor/ts-node-dev) to boot and reload your projects when running in typescript mode.

Javascript projects can do a similar thing via the nodemon (https://nodemon.io/) package

actionhero - v20.0.0

Published by evantahler about 5 years ago

Always prefer actionhero in node_modules

Related to https://github.com/actionhero/ah-swagger-plugin/pull/6

We have changed how Actionhero loads itself to always prefer components in node_modules relative to the cwd (current working directory):

Pros

  • There is no change to the behavior or a normal actionhero project
  • Globally installed Actionhero (npm install -g actionhero) is now resistant to minor version changes between projects
  • Allows plugins to install a version of actionhero as a devDependancy, and for us to boot the project and not have conflicting paths to source actionhero from. You can now just npm start (./node_modules/.bin/actionhero) in your plugins to start a server to run your plugins

Cons

  • If you start actoinhero from a dameon (like forever) without first cd-ing to the proper directory first things might not work depending on your load paths.
  • Slightly slower boot time (as we are checking if files exist before trying to load them).
  • Things (may) weird with yarn/lerna workspaces

This is a breaking change

Via https://github.com/actionhero/actionhero/pull/1338

Create tests for actions and tasks when generating via CLI

Completes https://github.com/actionhero/actionhero/issues/1005

When generating a new action or task via the CLI, a template test will also now be creates in __tests__. This will help encourage better testing of your actionhero projects. Of course, you can always delete the test files if you don't want it.

Adds api.config.general.paths.test as setting in ./config/api.js which defaults to [path.join(__dirname, '/../__tests__')]

This is a breaking change due to the new path

Via https://github.com/actionhero/actionhero/pull/1332

Add custom http status code with error object

Currently, we have to add the custom error response code like this:
data.connection.rawConnection.responseHttpCode = 404
We can use the error.code that already exists in the error object

Now in action, you can do something like this :

const raiseNotFound = <your-condition>
if(raiseNotFound) {
  const notFoundError = new Error(<msg>)
  notFoundError.code = 404
   throw notFoundError
}

via https://github.com/actionhero/actionhero/pull/1334

findEnqueuedTasks

Adds api.specHelper.findEnqueuedTasks to write tests that check that task was enqueued!

describe('task testing', () => {
  beforeEach(async () => {
    await api.resque.queue.connection.redis.flushdb()
  })

  test('detect that a task was enqueued to run now', async () => {
    await api.tasks.enqueue('regularTask', { word: 'testing' })
    const found = await api.specHelper.findEnqueuedTasks('regularTask')
    expect(found.length).toEqual(1)
    expect(found[0].args[0].word).toEqual('testing')
    expect(found[0].timestamp).toBeNull()
  })
})

via https://github.com/actionhero/actionhero/pull/1331

Misc

actionhero - v19.2.2

Published by evantahler about 5 years ago

  • Update Dependancies
  • Updates CircleCI testing scheme
  • Update bootstrap css used for example pages and demo site
actionhero - v19.2.1

Published by evantahler over 5 years ago

v19.2.1

Generated File Fixes for Satndard.js

Update test example and generated initializers so that they pass Standard.js checks

by @evanthaler via https://github.com/actionhero/actionhero/commit/06158ad3b57bfc451506f27e7510bea29ebeb7d8

actionhero - v19.2.0

Published by evantahler over 5 years ago

Actionhero v19.2.0

Boot Loader for Actionhero

When creating a new Actionhero project, there is a now a top-level boot.js file. You can use this new file to load or instantiate troublesome packages into your project that really want to be the first thing you load. Packages like newrelic or dotenv are these types of packages. Another use-case would be to configure your environment via an external source.

You can see the contents of boot.js to add to an existing project here https://github.com/actionhero/actionhero/blob/master/bin/templates/boot.js

Via https://github.com/actionhero/actionhero/pull/1311 by @chimmelb

reEnqueuePeriodicTaskIfException

Now, if a periodic task fails, it will still be run again. This behavior is what the majority of Actionhero uses had expected was happening all along, so hopefully this change is less surprising for new Acitonhero users.

A new option has been added to tasks, reEnqueuePeriodicTaskIfException with the default value of true. If you want your tasks to not be re-enqueued should they throw an exception, you can set reEnqueuePeriodicTaskIfException = false.

Via https://github.com/actionhero/actionhero/pull/1309 and https://github.com/actionhero/actionhero/commit/72fb343d5a0005ffa8e1f7550ca15c6fd169f82b by @dasagan

Updated logging levels

This change updates Actionhero's internal logging levels to more closely match The syslog protocol (RFC 5424). The details can be seen in the Pull Request.

Via https://github.com/actionhero/actionhero/pull/1314 by @aurasalexander

api.config.general.developmentModeForceRestart

This new option updates ActionHero's development mode to "full" restart when an Action or Task changes, rather than a soft restart. This can be handy if you add a new initializer, param, or route.

Via https://github.com/actionhero/actionhero/pull/1313 by @aurasalexander

actionhero - v19.1.4

Published by evantahler over 5 years ago

Misc

  • Update Dependancies to latest versions
actionhero - v19.1.3

Published by evantahler over 5 years ago

v19.1.3

Async connection.create middleware

Extend resque queue connection options from config

Misc

  • Test node v11
  • Update Dependancies
actionhero - v19.1.2

Published by evantahler over 5 years ago

Added strict transport security header as a default in web server config

Update config merge behavior to not clobber data with empty objects

Flatten task logs so they appear when logged to the CLI

actionhero - v19.1.1: Websocket Errors

Published by evantahler almost 6 years ago

Ensure that response.error is set for middleware errors in webscoket clients

When an error fails for a websocket client, we return response.error. However, if a say or roomAdd fails for the same client, we do not set response.error... now we do!

Update contributing docs

Add some more documentation about how you might contribute to ActionHero

actionhero - V19.1.0: Console Logging update and fixes

Published by gcoonrod almost 6 years ago

Console Logging

  • The console logger now appends any additional parameters passed to the logging function as a list of key-value pairs.
    • by @evantahler via #1268

General Fixes

  • Docs updates
    • by @evantahler and @etorrejon via 7dc82664607b12c164e61e9758376d14611af967
  • Setting web#urlPathForFiles to null now disables file server
    • by @evantahler via #1270
  • Added examples of Action versioning
    • by @evantahler via c424e41

Dependency updates

Dependency From Version To Version
ioredis ^4.1.0 ^4.3.0
primus ^7.2.3 ^7.3.2
qs ^6.5.2 ^6.6.0
ws ^6.1.0 ^6.1.2
mime ^2.3.1 ^2.4.0
docdash ^1.0.0 ^1.0.1
actionhero - v19.0.4: Chat and Redis fixes

Published by evantahler about 6 years ago

And of course...

  • stabilize flaky socket server tests
  • updated all dependancies to latest stable version
  • various documentation updates
actionhero - v17.1.3 Documentation Update

Published by evantahler about 6 years ago

Bringing the changes from #1243 in so we can build the docs for this version

actionhero - v19.0.3: documentation update

Published by evantahler about 6 years ago

Bringing the changes from #1243 in so we can build the docs for this version

actionhero - v18.1.4: documentation update

Published by evantahler about 6 years ago

Bringing the changes from https://github.com/actionhero/actionhero/pull/1243 in so we can build the docs for this version

actionhero - v19.0.2: Cluster Fixes

Published by evantahler over 6 years ago

Tasks and Cluster

  • Better rendering of uncaughtException stack traces in from cluster. We can now log much of the stack trace, including line numbers of the offending promise.
  • Log when a stuck worker is cleared by node-resque scheduler as a warning.

Misc

  • Update all packages to latest version, including node-resue. There was a fix in node-resque to address a case in which the process wouldn't properly wait for an in-progress task to complete. This was fixed in node-resque v5.3.1