synchrozine

package module
v4.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 25, 2021 License: MIT Imports: 3 Imported by: 0

README

synchrozine

Build Status

Synchrozine is an instrument for synchronization of multiple goroutines over a single channel. It provides the main channel (chan error), as well as tools for complete synchronization and receivers a channels list to send finish signals to goroutines.

Synchrozine supports the startup synchronization and thread-safe injections.

Installation

go mod init github.com/my/repo
go get github.com/Devoter/synchrozine/v4

Usage

It is easy to use Synchrozine. We have five lifecycle steps:

  1. Goroutines declaration
  2. Goroutines registration
  3. Startup synchronization
  4. Injection
  5. Final synchronization
Goroutines declaration

At first you should declare that a goroutine will be registered. Call Add() (or AddMany(int)) before start the goroutine(s).

synchro.Add()
go func() {
	// do something
}()
Goroutines registration

The next step is to register the declared goroutine. Call Done() before exit from the goroutine, get and listen a finish channel (Append()).

go func() {
	defer synchro.Done()

	finishChan := synchro.Append()

	for {
		select {
		case <-finishChan:
			return
		case <-time.After(100 * time.Millisecond): // any event
			// do something
		}
	}
}
Startup synchronization

Startup synchronization is optional, but if you want to be sure that all controlled goroutines have registered successfully call StartSync() in the parent goroutine.

synchro.StartSync(func() context.Context { return context.TODO() })
Injection

It is important that Inject() does not stops controlled goroutines. It just sends a message to the Synchrozine instance. This is a non-blocking method regardless of number of calls.

synchro.Inject(fmt.Errorf("stop all"))
Final synchronization

In your parent goroutine insert a Sync() call. This method will wait for the injection. After that, it will have broadcast finish signals to controlled goroutines and wait for synchronization. This is a blocking method.

synchro.Sync(func() context.Context { return context.TODO() })
Example
package main

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

	"github.com/Devoter/synchrozine/v4"
)

func main() {
	listen := flag.String("listen", ":8080", "HTTP listen address")

	flag.Parse()

	synchro := synchrozine.New()

	// Waiting for sigint or sigterm
	go func() {
		c := make(chan os.Signal)
		signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
		synchro.Inject(fmt.Errorf("%s", <-c))
		log.Println("signal received")
	}()

	go func() {
		log.Println("starting server...")
		log.Println("addr", *listen)
		synchro.Inject(http.ListenAndServe(*listen, nil))
		log.Println("server stopped")
	}()

	synchro.Add()
	go func() {
		defer synchro.Done()

		finishChan := synchro.Append()

		const increment = 5
		var counter int

		for {
			// do something
			select {
			case <-finishChan:
				log.Println("finish something")
				return
			case <-time.After(increment * time.Second):
				counter += increment
				log.Printf("%d seconds left\n", counter)
			}
		}
	}()

	ctx := context.Background()
	var cancel context.CancelFunc

	makeStartupCtx := func() context.Context {
		ctx, cancel = context.WithTimeout(ctx, 10 * time.Second) // wait 10 seconds for startup

		return ctx
	}
	
	defer func() { cancel() }()

	err := synchro.StartupSync(makeStartupCtx) // optional, just if you want to be sure that all goroutines have started
	if err != nil {
		log.Printf("Startup operation failed by the reason: [%v]\n", err)
		os.Exit(1)
	}

	syncCtx = context.Background()
	var syncCancel context.CancelFunc

	makeSyncCtx := func() context.Context {
		syncCtx, syncCancel = context.WithTimeout(ctx, 10 * time.Second) // wait 10 seconds for sync

		return syncCtx
	}
	
	defer func() { syncCancel() }()

	log.Println("exit: ", synchro.Sync(makeSyncCtx))
}

License

MIT

Documentation

Overview

Package synchrozine provides an instrument for synchronization of multiple goroutines over a single channel. It provides the main channel (`chan error`), as well as tools for complete synchronization and receivers a channels list to send finish signals to goroutines.

Synchrozine supports the startup synchronization and thread-safe injections.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Synchrozine

type Synchrozine struct {
	// contains filtered or unexported fields
}

Synchrozine is an instrument for synchronization of multiple goroutines over a single channel. It provides the main channel (`chan error`), as well as tools for complete synchronization and receives a channels list to send finish signals to goroutines.

func New

func New() *Synchrozine

New creates a initialized instance of Synchrozine.

func (*Synchrozine) Add

func (s *Synchrozine) Add()

Add increments a counter of controlled goroutines.

func (*Synchrozine) AddMany added in v4.0.2

func (s *Synchrozine) AddMany(count int)

AddMany increments a counter of controlled goroutines on the specified value.

func (*Synchrozine) Append

func (s *Synchrozine) Append() <-chan bool

Append creates a buffered receiver channel, adds it to the receivers list and returns for as read-only channel.

func (*Synchrozine) Done

func (s *Synchrozine) Done()

Done decrements a counter of controlled goroutines.

func (*Synchrozine) Inject

func (s *Synchrozine) Inject(err error)

Inject sends a sync message.

func (*Synchrozine) StartupSync

func (s *Synchrozine) StartupSync(ctxFactory func() context.Context) error

StartupSync waits for all appended goroutines to start.

func (*Synchrozine) Sync

func (s *Synchrozine) Sync(ctxFactory func() context.Context) error

Sync waits for a sync message, sends messages to receivers, and waits for goroutines completion.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL