🚧 Flexible mechanism to make execution flow interruptible.

🚧 breaker Awesome Go

Flexible mechanism to make execution flow interruptible.

Build Documentation Quality Template Coverage Mirror

💡 Idea

The breaker carries a cancellation signal to interrupt an action execution.

var NewYear = time.Time{}.AddDate(time.Now().Year(), 0, 0)

interrupter := breaker.Multiplex(
	breaker.BreakByContext(context.WithTimeout(req.Context(), time.Minute)),
	breaker.BreakByDeadline(NewYear),
	breaker.BreakBySignal(os.Interrupt),
)
defer interrupter.Close()

<-interrupter.Done() // wait context cancellation, timeout or interrupt signal

A full description of the idea is available here.

🏆 Motivation

I have to make modules github.com/kamilsk/retry/v5:

if err := retry.Retry(breaker.BreakByTimeout(time.Minute), action); err != nil {
	log.Fatal(err)
}

and github.com/kamilsk/semaphore/v5:

if err := semaphore.Acquire(breaker.BreakByTimeout(time.Minute), 5); err != nil {
	log.Fatal(err)
}

more consistent and reliable.

Additionally, I want to implement a Graceful Shutdown on the same mechanism.

🤼‍♂️ How to

Do HTTP request with retries

interrupter := breaker.Multiplex(
	breaker.BreakBySignal(os.Interrupt, syscall.SIGINT, syscall.SIGTERM),
	breaker.BreakByTimeout(timeout),
)
defer interrupter.Close()

ctx := breaker.ToContext(interrupter)
ctx = context.WithValue(ctx, header, "...")

req, err := http.NewRequestWithContext(ctx, http.MethodGet, server.URL, nil)
if err != nil {
	panic(err)
}

var resp *http.Response
action := func(ctx context.Context) (err error) {
	req = req.Clone(ctx)

	source := ctx.Value(header).(string)
	req.Header.Set(header, source)

	resp, err = http.DefaultClient.Do(req)
	return err
}

if err := retry.Do(ctx, action); err != nil {
	panic(err)
}
Full example
package main

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
	"os"
	"syscall"
	"time"

	"github.com/kamilsk/breaker"
	"github.com/kamilsk/retry/v5"
)

func main() {
	const (
		header  = "X-Message"
		timeout = time.Minute
	)

	server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
		time.Sleep(timeout / 10)
		_, _ = rw.Write([]byte(req.Header.Get(header)))
	}))
	defer server.Close()

	interrupter := breaker.Multiplex(
		breaker.BreakBySignal(os.Interrupt, syscall.SIGINT, syscall.SIGTERM),
		breaker.BreakByTimeout(timeout),
	)
	defer interrupter.Close()

	ctx := breaker.ToContext(interrupter)
	ctx = context.WithValue(ctx, header, "flexible mechanism to make execution flow interruptible")

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, server.URL, nil)
	if err != nil {
		panic(err)
	}

	var resp *http.Response
	action := func(ctx context.Context) (err error) {
		req = req.Clone(ctx)

		source := ctx.Value(header).(string)
		req.Header.Set(header, source)

		resp, err = http.DefaultClient.Do(req)
		return err
	}

	if err := retry.Do(ctx, action); err != nil {
		fmt.Println("error:", err)
		return
	}
	_, _ = io.Copy(os.Stdout, resp.Body)
}

Play it!

Graceful Shutdown HTTP server

interrupter := breaker.Multiplex(
	breaker.BreakBySignal(os.Interrupt, syscall.SIGINT, syscall.SIGTERM),
	breaker.BreakByTimeout(timeout),
)
defer interrupter.Close()

server := http.Server{
	BaseContext: func(net.Listener) context.Context {
		return breaker.ToContext(interrupter)
	},
}
go func() {
	if err := server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
		log.Fatal(err)
	}
}()

<-interrupter.Done()
if errors.Is(interrupter.Err(), breaker.Interrupted) {
	if err := server.Shutdown(context.TODO()); err != nil {
		panic(err)
	}
}
Full example
package main

import (
	"context"
	"errors"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"syscall"
	"time"

	"github.com/kamilsk/breaker"
)

func main() {
	const timeout = time.Minute

	interrupter := breaker.Multiplex(
		breaker.BreakBySignal(os.Interrupt, syscall.SIGINT, syscall.SIGTERM),
		breaker.BreakByTimeout(timeout),
	)
	defer interrupter.Close()

	server := http.Server{
		Addr:    ":8080",
		Handler: http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {}),
		BaseContext: func(net.Listener) context.Context {
			return breaker.ToContext(interrupter)
		},
	}
	go func() {
		if err := server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
			log.Fatal(err)
		}
	}()

	<-interrupter.Done()
	if err := interrupter.Err(); errors.Is(err, breaker.Interrupted) {
		if err := server.Shutdown(context.TODO()); err != nil {
			panic(err)
		}
	}
	fmt.Println("graceful shutdown")
}

Play it!

🧩 Integration

The library uses SemVer for versioning, and it is not BC-safe through major releases. You can use go modules to manage its version.

$ go get github.com/kamilsk/breaker@latest

🤲 Outcomes

Console tool to execute commands for a limited time

The example shows how to execute console commands for ten minutes.

$ date
# Thu Jan  7 21:02:21
$ breakit after 10m -- server run --port=8080
$ breakit ps
# +--------------------------+----------------------------+----------+----------+
# | Process                  | Status                     | Since    | Until    |
# +--------------------------+----------------------------+----------+----------+
# | server run --port=8080   | exit 1; panic: database... | 21:02:36 | -        |
# +--------------------------+----------------------------+----------+----------+
# |                          |                            |    Total |        1 |
# +--------------------------+----------------------------+----------+----------+
$ breakit after 10m -- database run --port=5432
$ breakit after 10m delay 5s -- server run --port=8080
$ breakit ps
# +--------------------------+----------------------------+----------+----------+
# | Process                  | Status                     | Since    | Until    |
# +--------------------------+----------------------------+----------+----------+
# | database run --port=5432 | running                    | 21:04:09 | 21:14:09 |
# | server run --port=8080   | delayed                    | 21:04:30 | 21:14:25 |
# +--------------------------+----------------------------+----------+----------+
# |                          |                            |    Total |        2 |
# +--------------------------+----------------------------+----------+----------+

See more details here.

made with ❤️ for everyone

Similar Resources

A universal mechanism to manage goroutine lifecycles

A universal mechanism to manage goroutine lifecycles

Dec 29, 2022

Multithreaded key value pair store using thread safe locking mechanism allowing concurrent reads

Multithreaded key value pair store using thread safe locking mechanism allowing concurrent reads

Project Amnesia A Multi-threaded key-value pair store using thread safe locking mechanism allowing concurrent reads. Curious to Try it out?? Check out

Oct 29, 2022

The Hyperscale InputFilter library provides a simple inputfilter chaining mechanism by which multiple filters and validator may be applied to a single datum in a user-defined order.

Hyperscale InputFilter Branch Status Coverage master The Hyperscale InputFilter library provides a simple inputfilter chaining mechanism by which mult

Oct 20, 2021

Study project that uses Apache Kafka as syncing mechanism between two databases, with producers and consumers written in Go.

Kafka DB Sync Study project that uses Apache Kafka as syncing mechanisms between a monolith DB and a microservice. The main purpose of this project is

Dec 5, 2021

One Time Passwords (OTPs) are an mechanism to improve security over passwords alone.

otp: One Time Password utilities Go / Golang Why One Time Passwords? One Time Passwords (OTPs) are an mechanism to improve security over passwords alo

Jan 7, 2023

Goya circuit is a circuit breaker mechanism implementation in microservices.

Goya-Circuit: 类似于Hystrix的熔断器实现 Goya circuit is a circuit breaker mechanism implementation in microservices. It can prevent the whole link avalanche ca

Mar 8, 2022

Automatically capture all potentially useful information about each executed command (as well as its output) and get powerful querying mechanism

Automatically capture all potentially useful information about each executed command (as well as its output) and get powerful querying mechanism

nhi is a revolutionary tool which automatically captures all potentially useful information about each executed command and everything around, and delivers powerful querying mechanism.

Nov 29, 2022

Utility library that uses Go generics mechanism

golang-generics-util Utility library that explores Go generics (1.18) xsync Sync

Dec 11, 2022

Go-gin-jwt - Secure web api using jwt token and caching mechanism

Project Description This project demonstrate how to create api and secure it wit

Jan 27, 2022

QR secrets is a cryptographically secure mechanism to store secret data with the highest levels of security and store it on physical paper.

QR secrets is a cryptographically secure mechanism to store secret data with the highest levels of security and store it on physical paper.

QR Secrets QR secrets is a cryptographically secure mechanism to store secret data with the highest levels of security. Incorporating; AES256-GCM-HKDF

Jan 12, 2022

Go library containing a collection of financial functions for time value of money (annuities), cash flow, interest rate conversions, bonds and depreciation calculations.

go-finance Go library containing a collection of financial functions for time value of money (annuities), cash flow, interest rate conversions, bonds

Jan 2, 2023

Hunch provides functions like: All, First, Retry, Waterfall etc., that makes asynchronous flow control more intuitive.

Hunch provides functions like: All, First, Retry, Waterfall etc., that makes asynchronous flow control more intuitive.

Hunch Hunch provides functions like: All, First, Retry, Waterfall etc., that makes asynchronous flow control more intuitive. About Hunch Go have sever

Dec 8, 2022

Framework for performing work asynchronously, outside of the request flow

Framework for performing work asynchronously, outside of the request flow

JobRunner JobRunner is framework for performing work asynchronously, outside of the request flow. It comes with cron to schedule and queue job functio

Jan 1, 2023

Flow-based and dataflow programming library for Go (golang)

Flow-based and dataflow programming library for Go (golang)

GoFlow - Dataflow and Flow-based programming library for Go (golang) Status of this branch (WIP) Warning: you are currently on v1 branch of GoFlow. v1

Dec 30, 2022

This static analysis tool works to ensure your program's data flow does not spill beyond its banks.

Go Flow Levee This static analysis tool works to ensure your program's data flow does not spill beyond its banks. An input program's data flow is expl

Dec 1, 2022

A simulated-annealing approach to solving a max-flow removal problem

A simulated-annealing approach to solving a max-flow removal problem

RESISTANCE IS FUTILE How to run: Install the latest version of golang to your computer (1.16?) Run a postgres instance on your computer attatched to p

Aug 26, 2022

Contracts for the versus-flow.art project

Versus Flow Auction Contract This is a git repo for the cadence contrats for versus@flow. Follow the guide below to set it up and test locally in the

Jul 19, 2022

A general-purpose Cadence contract for trading NFTs on Flow

NFT Storefront The NFT storefront is a general-purpose Cadence contract for trading NFTs on Flow. NFTStorefront uses modern Cadence run-time type faci

Dec 24, 2022

manipulate WireGuard with OpenID Connect Client Initiated Backchannel Authentication(CIBA) Flow

oidc-wireguard-vpn manipulate WireGuard with OpenID Connect Client Initiated Backchannel Authentication(CIBA) Flow Requirements Linux WireGuard nftabl

Oct 7, 2022
Hunch provides functions like: All, First, Retry, Waterfall etc., that makes asynchronous flow control more intuitive.
Hunch provides functions like: All, First, Retry, Waterfall etc., that makes asynchronous flow control more intuitive.

Hunch Hunch provides functions like: All, First, Retry, Waterfall etc., that makes asynchronous flow control more intuitive. About Hunch Go have sever

Dec 8, 2022
Simply way to control goroutines execution order based on dependencies
Simply way to control goroutines execution order based on dependencies

Goflow Goflow is a simply package to control goroutines execution order based on dependencies. It works similar to async.auto from node.js async packa

Dec 8, 2022
Go asynchronous simple function utilities, for managing execution of closures and callbacks
Go asynchronous simple function utilities, for managing execution of closures and callbacks

⚙️ gollback gollback - Go asynchronous simple function utilities, for managing execution of closures and callbacks ?? ABOUT Contributors: Rafał Lorenz

Dec 29, 2022
A library for performing OAuth Device flow and Web application flow in Go client apps.
A library for performing OAuth Device flow and Web application flow in Go client apps.

oauth A library for Go client applications that need to perform OAuth authorization against a server, typically GitHub.com. Traditionally,

Dec 30, 2022
A limited Flow Access API which runs outside of the Flow Network using the DPS

Access API Flow DPS implements the Flow Access API Specification, except for the following endpoints: SendTransaction GetLatestProtocolStateSnapshot G

Jul 28, 2022
keeper is package for Go that provides a mechanism for waiting a result of execution function until context cancel.

keeper is package for Go that provides a mechanism for waiting a result of execution function until context cancel.

Apr 18, 2022
A wrapper for leader election mechanism in Kubernetes

Kubernetes Leader Election Library for Go This library provides a thin wrapper for kubernetes leader election. It can be used to elect a leader betwee

Dec 24, 2022
Deece is an open, collaborative, and decentralised search mechanism for IPFS
Deece is an open, collaborative, and decentralised search mechanism for IPFS

Deece Deece is an open, collaborative, and decentralised search mechanism for IPFS. Any node running the client is able to crawl content on IPFS and a

Oct 29, 2022
goInterLock is golang job/task scheduler with distributed locking mechanism (by Using Redis🔒).
goInterLock is golang job/task scheduler with distributed locking mechanism (by Using Redis🔒).

goInterLock is golang job/task scheduler with distributed locking mechanism. In distributed system locking is preventing task been executed in every instant that has the scheduler,

Dec 5, 2022
Declarative CLI Version manager. Support Lazy Install and Sharable configuration mechanism named Registry. Switch versions seamlessly

aqua Declarative CLI Version manager. Support Lazy Install and Sharable configuration mechanism named Registry. Switch versions seamlessly. Index Slid

Dec 29, 2022