- Go 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
checks / Vet / Test / Lint (push) Successful in 2m8s
- Метка alt маппится на образ gitrepo.ru/neonxp/base, container: больше не нужен - Три раннера вместо одного последовательного - параллелизм |
||
| .forgejo/workflows | ||
| .golangci.yml | ||
| fsm.go | ||
| fsm_test.go | ||
| go.mod | ||
| LICENSE | ||
| README.md | ||
| types.go | ||
fsm - Конечный автомат для Go
fsm - это реализация конечного автомата (Finite State Machine) для языка
программирования Go, в которой бизнес-логика и решение о переходе живут
внутри функций состояний. Машина исполняет состояния одну за другой и
валидирует каждый переход по объявленным рёбрам графа.
Особенности
- Минимальный API: одна структура и два метода -
OnиRun - Функциональные состояния: бизнес-логика и решение о переходе - внутри функции состояния, машина только исполняет и валидирует
- Валидация переходов: переход по необъявлённому ребру - ошибка
ErrInvalidTransition, состояние не меняется - Zero-value ready: автомат не требует конструктора - нулевое значение
fsm.FSMготово к использованию - Никаких паник: все ошибки возвращаются как
errorс сентинеламиErrInvalidTransitionиErrDuplicateEdge - Потокобезопасность: все операции синхронизированы с использованием
sync.Mutex
Установка
go get go.neonxp.ru/fsm
Использование
package main
import (
"context"
"fmt"
"log"
"go.neonxp.ru/fsm"
)
var idle, running fsm.State
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Функция состояния содержит бизнес-логику и решает, куда переходить
idle = fsm.State(func(ctx context.Context) *fsm.State {
select {
case <-tasks:
return &running
case <-ctx.Done():
return nil // терминальное состояние
}
})
running = fsm.State(func(ctx context.Context) *fsm.State {
if err := process(ctx); err != nil {
return &idle // ошибка - возвращаем задачу
}
return nil
})
var m fsm.FSM
// Объявляем допустимые переходы
must(m.On(&idle, &running))
must(m.On(&running, &idle))
// Машина исполняет состояния и валидирует каждый переход
if err := m.Run(ctx, &idle); err != nil {
log.Fatal(err)
}
}
func must(err error) {
if err != nil {
panic(err)
}
}
API
type State func(ctx context.Context) *State
Функциональное состояние: инкапсулирует бизнес-логику и решение о переходе,
возвращая следующее состояние. nil - терминальное состояние. Состояния
объявляются переменными, их идентичность - адрес переменной.
func (f *FSM) On(from, to *State) error
Объявляет допустимый переход между состояниями from и to. При дубликате
ребра возвращает ошибку, обёртывающую ErrDuplicateEdge. Переход в
терминальное состояние (nil) объявлять не нужно.
func (f *FSM) Run(ctx context.Context, initial *State) error
Запускает цикл: исполняет текущее состояние, валидирует переход к
возвращённому состоянию и повторяет, пока функция состояния не вернёт nil
или контекст не будет отменён. При необъявленном переходе возвращает
ошибку, обёртывающую ErrInvalidTransition.
Нюансы
- Идентичность функционального состояния - адрес переменной, поэтому функции
состояний возвращают указатели на объявленные переменные (
return &running) - Переход в терминальное состояние (
nil) всегда допустим и не объявляется - Нулевое значение
FSMбез объявленных рёбер допускает только переход в терминальное состояние - Копирование автомата запрещено: используйте указатель
*FSM(проверяетсяgo vet) nil-контекст безопасен: контекст передаётся только в функции состояний
Лицензия
Этот проект лицензирован в соответствии с GNU General Public License версии 3 (GPLv3). Подробности смотрите в файле LICENSE.
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2026 Alexander NeonXP Kiryukhin <i@neonxp.ru>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Ссылки
- Репозиторий: https://gitrepo.ru/neonxp/fsm.git
- Автор: Alexander NeonXP Kiryukhin i@neonxp.ru
English Version
fsm is an implementation of a Finite State Machine for the Go programming
language in which the business logic and the transition decision live inside
the state functions. The machine executes the states one by one and
validates every transition against the declared edges of the graph.
Features
- Minimal API: one struct and two methods -
OnandRun - Functional states: the business logic and the transition decision live inside the state function, the machine only executes and validates
- Transition validation: a transition over an undeclared edge is an
ErrInvalidTransitionerror, the state remains unchanged - Zero-value ready: The machine does not require a constructor - the
zero value of
fsm.FSMis ready to use - No panics: All errors are returned as
errorwith theErrInvalidTransitionandErrDuplicateEdgesentinels - Thread-safe: All operations are synchronized using
sync.Mutex
Installation
go get go.neonxp.ru/fsm
Usage
package main
import (
"context"
"log"
"go.neonxp.ru/fsm"
)
var idle, running fsm.State
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// The state function contains the business logic and decides where to
// transition
idle = fsm.State(func(ctx context.Context) *fsm.State {
select {
case <-tasks:
return &running
case <-ctx.Done():
return nil // terminal state
}
})
running = fsm.State(func(ctx context.Context) *fsm.State {
if err := process(ctx); err != nil {
return &idle // error - put the task back
}
return nil
})
var m fsm.FSM
// Declare allowed transitions
must(m.On(&idle, &running))
must(m.On(&running, &idle))
// The machine executes the states and validates every transition
if err := m.Run(ctx, &idle); err != nil {
log.Fatal(err)
}
}
func must(err error) {
if err != nil {
panic(err)
}
}
API
type State func(ctx context.Context) *State
A functional state: encapsulates the business logic and the transition
decision, returning the next state. nil is a terminal state. States are
declared as variables, their identity is the address of the variable.
func (f *FSM) On(from, to *State) error
Declares an allowed transition between states from and to. Returns an
error wrapping ErrDuplicateEdge on a duplicate edge. A transition to a
terminal state (nil) needs no declaration.
func (f *FSM) Run(ctx context.Context, initial *State) error
Starts the loop: executes the current state, validates the transition to
the returned state and repeats until a state function returns nil or the
context is canceled. Returns an error wrapping ErrInvalidTransition on an
undeclared transition.
Caveats
- The identity of a functional state is the address of the variable, so
state functions return pointers to the declared variables
(
return &running) - A transition to a terminal state (
nil) is always allowed and is not declared - The zero value of
FSMwithout declared edges allows only transitions to the terminal state - Copying the machine is forbidden: use the
*FSMpointer (checked bygo vet) - A
nilcontext is safe: the context is only passed to state functions
License
This project is licensed under the GNU General Public License version 3 (GPLv3). See the LICENSE file for details.
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2026 Alexander NeonXP Kiryukhin <i@neonxp.ru>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Links
- Repository: https://gitrepo.ru/neonxp/fsm.git
- Author: Alexander NeonXP Kiryukhin i@neonxp.ru