Skip to content

Lightweight Framework for Amazon Simple Workflow Service written in TypeScript and Rx

License

MIT, MIT licenses found

Licenses found

MIT
LICENSE
MIT
LICENSE.md
Notifications You must be signed in to change notification settings

adamrecsko/light-workflow-js

Repository files navigation

light-workflow-js

Build Status

A library to create, run and orchestrate AWS SWF workflow. Written in TypeScript and heavily relies on RxJS.

Documentation - You can find a documentation here

Getting Started

  $ git clone https://github.com/adamrecsko/light-workflow-js.git
  $ cd light-workflow-js
  $ yarn install

Prerequisites

You need node.js and yarn to be installed before a start.

    $ apt-get install nodejs
    $ npm install yarn -g

For running a workflow on AWS you need aws credentials properly setup on your development environment and a registered AWS SWF domain.

Running the tests

    $ yarn test

Running linter

Explain what these tests test and why

   $ yarn lint

Example

HelloWorld Application

For examples please check the examples folder.

Actor implementation

import 'reflect-metadata';
import 'zone.js';

const HELLO_WORLD_ACTOR = Symbol('HELLO_WORLD_ACTOR');

export interface HelloWorld {
  formatText(text: string): Observable<string>;
  printIt(text: string): Observable<string>;
}

@injectable()
export class HelloWorldImpl implements HelloWorld {
  private printer(text: string) {
    console.log(text);
  }

  @activity()
  @version('1')
  formatText(text: string): Observable<string> {
    return of('Hello' + text);
  }

  @activity()
  @version('1')
  @description('print the text out')
  printIt(text: string): Observable<string> {
    return of(text).do((text: string) => {
      this.printer(text);
    });
  }
}

Workflow implementation

export const HELLO_WORLD_WORKFLOW = Symbol('HELLO_WORLD_WORKFLOW');


export interface HelloWorldWorkflow {
  helloWorld(text: string): Promise<string>;
}


@injectable()
export class HelloWorldWorkflowImpl implements HelloWorldWorkflow {
  @actorClient
  @inject(HELLO_WORLD_ACTOR)
  private actor: HelloWorld;

  @workflow()
  async helloWorld(text: string) {
    const formattedText = await this.actor.formatText(text).toPromise();
    const printedText = await this.actor.printIt(formattedText).toPromise();
    return printedText;
  }
}

You can handle activity exceptions with try catch

  @workflow()
  async helloWorldWithErrorHandling() {
    try {
      await this.actor.throwException().toPromise();
    } catch (e) {
      if (e instanceof FailedException) {
        return 'Error handled';
      }
      throw e;
    }
  }
  

Or you can use observables to create a flow

  @workflow()
  helloWorldHandleErrorWithObservables() {
    return this.actor.throwException().catch((err) => {
      if (err instanceof FailedException) {
        return Observable.of('Error handled, no problem!');
      }
      return Observable.throw(err);
    });
  }

Or with lettable operators

  @workflow()
  helloWorldHandleErrorWithObservables() {
    const errorHandler = catchError(err => of('Error handled, no problem!'));
    return this.actor.throwException().let(errorHandler);
  }

You can also reschedule an activity

  
   @workflow()
   async helloWorkflowWithRetry() {
      try {
        await this.actor.firstTryTimeOut(0).toPromise();
      } catch (e) {
        if (e instanceof TimeoutException) {
          // Don't worry it is just a timeout
          return await this.actor.firstTryTimeOut(1).toPromise();
        }
        throw Error('Unknown error');
      }
    }
  

For more examples please check the examples folder

Application implementation

@injectable()
@configuration(new ApplicationConfiguration(new SWF({ region: 'us-east-1' })))
@services([
  {
    impl: HelloWorldImpl,
    key: HELLO_WORLD_ACTOR,
  },
  {
    impl: HelloWorldWorkflowImpl,
    key: HELLO_WORLD_WORKFLOW,
  },
])
export class MyApp {
  public static domain = 'test-domain';
  @inject(HELLO_WORLD_WORKFLOW)
  @workflowClient
  private workflow: HelloWorldWorkflow;
  @inject(WORKFLOWS)
  private workflows: Workflows;
  @inject(WORKFLOW_WORKER_FACTORY)
  private workerFactory: WorkflowWorkerFactory;
  @inject(ACTOR_WORKER_FACTORY)
  private actorWorkerFactory: ActorWorkerFactory;

  public async startHelloWorld(text: string): Promise<string> {
    const start = this.workflows.createStarter(MyApp.domain, 'default');
    const workflowResult = await start(this.workflow.helloWorld, text);
    return workflowResult.runId;
  }

public createWorkflowWorker(): WorkflowWorker<HelloWorld> {
    return this.workerFactory.create(MyApp.domain, [{
      key: HELLO_WORLD_WORKFLOW,
      impl: HelloWorldWorkflowImpl,
    }]);
  }

  public createActorWorker(): ActorWorker {
    return this.actorWorkerFactory.create(MyApp.domain, [{
      key: HELLO_WORLD_ACTOR,
      impl: HelloWorldImpl,
    }]);
  }
}

How to start workers and workflow

async function boot() {
  const app = createApplication<MyApp>(MyApp);

  const workflowWorker = app.createWorklfowWorker();
  const actorWorker = app.createActorWorker();


  await workflowWorker.register().toPromise();
  await actorWorker.register().toPromise();

  workflowWorker.startWorker();
  actorWorker.startWorker();

  await  app.startHelloWorld('World');

}

// boot
// register workflow and activities

boot().catch(err => console.error(err));

Built With

Authors

  • Adam Recsko - Initial work

License

This project is licensed under the MIT License - see the LICENSE.md file for details

Acknowledgments

  • This library is under development and not production ready yet.

About

Lightweight Framework for Amazon Simple Workflow Service written in TypeScript and Rx

Topics

Resources

License

MIT, MIT licenses found

Licenses found

MIT
LICENSE
MIT
LICENSE.md

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published