All Projects → pvelx → triggerhook

pvelx / triggerhook

Licence: MIT license
Task scheduler

Programming Languages

go
31211 projects - #10 most used programming language
Makefile
30231 projects

Projects that are alternatives of or similar to triggerhook

Noel
A universal, human-centric, replayable javascript event emitter.
Stars: ✭ 158 (+351.43%)
Mutual labels:  event-driven
Event Driven Spring Boot
Example Application to demo various flavours of handling domain events in Spring Boot
Stars: ✭ 194 (+454.29%)
Mutual labels:  event-driven
Watermill
Building event-driven applications the easy way in Go.
Stars: ✭ 3,504 (+9911.43%)
Mutual labels:  event-driven
Rele
Easy to use Google Pub/Sub
Stars: ✭ 164 (+368.57%)
Mutual labels:  event-driven
Space Cloud
Open source Firebase + Heroku to develop, scale and secure serverless apps on Kubernetes
Stars: ✭ 3,323 (+9394.29%)
Mutual labels:  event-driven
Pos
Sample Application DDD, Reactive Microservices, CQRS Event Sourcing Powered by DERMAYON LIBRARY
Stars: ✭ 207 (+491.43%)
Mutual labels:  event-driven
Libwire
User space threading (aka coroutines) library for C resembling GoLang and goroutines
Stars: ✭ 149 (+325.71%)
Mutual labels:  event-driven
KDispatcher
Simple and light-weight event dispatcher for Kotlin
Stars: ✭ 64 (+82.86%)
Mutual labels:  event-driven
P
The P programming language.
Stars: ✭ 2,309 (+6497.14%)
Mutual labels:  event-driven
Bilibiliupload
Stream download and upload, not only for bilibili.
Stars: ✭ 232 (+562.86%)
Mutual labels:  event-driven
Newbe.claptrap
This is a frameworks with reactive, event sourcing and Actor pattern as basic theories. On top of this, developers can create "distributed", "scale out", and "easy to test" application more simply. Claptrap and it`s Minions is on the way.
Stars: ✭ 163 (+365.71%)
Mutual labels:  event-driven
Libuev
Lightweight event loop library for Linux epoll() family APIs
Stars: ✭ 170 (+385.71%)
Mutual labels:  event-driven
Dntframeworkcore
Lightweight and Extensible Infrastructure for Building Web Applications - Web Application Framework
Stars: ✭ 208 (+494.29%)
Mutual labels:  event-driven
Event Sourcing Jambo
An Hexagonal Architecture with DDD + Aggregates + Event Sourcing using .NET Core, Kafka e MongoDB (Blog Engine)
Stars: ✭ 159 (+354.29%)
Mutual labels:  event-driven
awesome-software-architecture
A curated list of awesome articles, videos, and other resources to learn and practice software architecture, patterns, and principles.
Stars: ✭ 1,594 (+4454.29%)
Mutual labels:  event-driven
Dapr
Dapr is a portable, event-driven, runtime for building distributed applications across cloud and edge.
Stars: ✭ 16,274 (+46397.14%)
Mutual labels:  event-driven
Qmq
QMQ是去哪儿网内部广泛使用的消息中间件,自2012年诞生以来在去哪儿网所有业务场景中广泛的应用,包括跟交易息息相关的订单场景; 也包括报价搜索等高吞吐量场景。
Stars: ✭ 2,420 (+6814.29%)
Mutual labels:  event-driven
keda-connectors
Generic connectors for Keda which can be used as worker images as part of scaleTargetRef.
Stars: ✭ 22 (-37.14%)
Mutual labels:  event-driven
azeroth-event
Lightweight event-driven framework
Stars: ✭ 18 (-48.57%)
Mutual labels:  event-driven
Dotnet New Caju
Learn Clean Architecture with .NET Core 3.0 🔥
Stars: ✭ 228 (+551.43%)
Mutual labels:  event-driven

Trigger Hook - delayed launch of tasks

Build Status GitHub release

Often in projects, there is a need to perform deferred tasks, such as sending email, push, and other tasks specific to the domain area of your application. Difficulties begin when the usual crontab is no longer enough, when batch processing is not suitable, when each task unit has its own execution time or it is assigned dynamically. To solve this problem, a Trigger Hook was created. You can build a task scheduler based on this library.

Principle of operation

Principle of operation

Task Description
Task a task whose launch time is not yet soon
Task a task whose launch time is coming soon
Task a task whose launch time has come
Task a task that was processed
Task not confirmed the status of the task in the database
Task command to delete

Life cycle tasks:

  • When creating a task, it gets into the database (square block) (red and yellow).
  • Tasks are loaded into memory (triangular block) if their start time is coming soon (red->yellow). This structure is implemented in the form of a prioritized queue (heap).
  • When the task execution time comes, it is sent for execution (yellow->green). An intermediate buffer is used before processing to compensate for peak loads.
  • If the task is successfully submitted, it is deleted from the database (green->blue). An intermediate buffer is used before deletion, also to compensate for peak loads.

The diagram shows some of the application metrics:

Metric Description
All Total number of tasks
Creating rate Number of created tasks (via the Create method) per unit of time.
Deleting rate Number of deleted tasks (via the Delete method) per unit of time.
Sending rate The number of processed tasks (via the Consume method) per unit of time.
Preloaded The number of tasks preloaded into memory.
Preloading rate The number of tasks loaded per unit of time.
Waiting for sending The number of tasks that have reached the execution time and are waiting to be sent to the consumer. The lower the value, the better. The presence of tasks in this metric indicates a reduced capacity of the task consumer.
Waiting for confirmation The number of tasks waiting for confirmation after sending. The last stage of working with the task. The lower the value, the better. The presence of tasks in this metric indicates slow work with the database.
Confirmation rate The number of confirmed tasks after sending per unit of time.

Demo

Use the demo Read the article

Features

  • Simple API.
  • Performing tasks with second precision.
  • High performance of sending tasks for execution. This is achieved through a simple task storage scheme, indexing, and multithreaded database access.
  • High peak performance. Tasks that will be completed soon are loaded into memory in advance. This is especially important, for example, if several hundred thousand tasks are assigned at one time.
  • The system is durable to failures. Only after the task is completed, the task is deleted from the database. This ensures that the task is sent for execution. The sudden stop of the application will not lead to inconsistent data in the database.
  • It is designed for a micro-service, event-driven architecture. It is easy to implement a fully asynchronous API.
  • The modular structure of the library. You can easily replace any part with your own implementation.
  • Monitoring the status of the application. Built-in performance monitoring adapter. Built-in adapter for error logging.

Benchmark

The main indicators of the task processing speed were measured.

Application server:

  • AWS EC2 Ubuntu 20
  • t2.micro
  • 1 vCPUs 2.5 GHz
  • 1 GiB RAM

Database server:

  • AWS RDS MySQL 8.0
  • db.t3.micro
  • 2 vCPUs
  • 1 GiB RAM
  • Network: 2085 Mbps
Test The duration of the test Average speed (tasks/sec) Number of tasks
Creating tasks 1m 11s 1396 100000
Deleting tasks 52s 1920 100000
Sending tasks (task status from red to blue) 498ms 200668 100000
Confirm tasks (the status of the task from the blue to the delete) 2s 49905 100000

Requirements

The project uses a MySQL database version 5.7 or 8

Quick start

The Create, Delete, and Consume methods are safe when used in multiple goroutines.

package main

import (
	"fmt"
	"log"
	"time"

	"github.com/pvelx/triggerhook"
	"github.com/pvelx/triggerhook/connection"
	"github.com/pvelx/triggerhook/domain"
	"github.com/satori/go.uuid"
)

func send(id string, execTime int64) error {
	// You have to trigger task in your app
	fmt.Printf("Task id:%s execTime:%d\n", id, execTime)
	return nil
}

func main() {
	tasksDeferredService := triggerhook.Build(triggerhook.Config{
		Connection: connection.Options{
			Host: "127.0.0.1:3306",
		},
	})

	go func() {
		for i := 0; i < 1000; i++ {
			task := domain.Task{
				Id:       uuid.NewV4().String(),
				ExecTime: time.Now().Add(time.Minute).Unix(),
			}
			if err := tasksDeferredService.CreateCtx(context.Background(), &task); err != nil {
				log.Fatalf("error creating task: %v", err)
			}

			// Delete each tenth task
			if i%10 == 0 {
				if err := tasksDeferredService.DeleteCtx(context.Background(), task.Id); err != nil {
					log.Fatalf("error deleting task: %v", err)
				}
			}
		}
	}()

	go func() {
		for {
			result := tasksDeferredService.Consume()
			task := result.Task()
			if err := send(task.Id, task.ExecTime); err != nil {
				result.Rollback()
			}
			result.Confirm()
		}
	}()

	if err := tasksDeferredService.Run(); err != nil {
		log.Fatalf("failed run trigger hook: %v", err)
	}
}

If the application crashes, there is a possibility that some tasks may not be confirmed in the database. When you restart the application, these tasks will be sent for execution again. This behavior is a trade-off in favor of providing fault tolerance. When your application receives a message from Trigger Hook, it should only execute the task once, and ignore it when it receives it again.

License

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

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].