qmuntal / stateless

Go library for creating finite state machines

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Provide API to return Is state machine has queued event

okhowang opened this issue · comments

I write a wrapper for stateless.StateMachine.
for run some function after trigger succeed.

func (sm *State Machine) FireCtx(ctx context.Context, trigger stateless.Trigger, args ...interface{}) error {
	if v, ok := ctx.Value(deferRunnerKey{}).(*deferRunner); !ok || v == nil {
		ctx = context.WithValue(ctx, deferRunnerKey{}, &deferRunner{})
	}
	err := sm.StateMachine.FireCtx(ctx, trigger, args...)
	if err == nil { // one more condition if trigger queued, defer function shouldn't be call
		defers := ctx.Value(deferRunnerKey{}).(*deferRunner) // nolint:errcheck
		for _, task := range defers.tasks {
			task(ctx)
		}
	}
	return err
}

but there is a bug when call Fire in StateMachine

func TestDeferTwice(t *testing.T) {
	counter := 0
	sm := &StateMachine{stateless.NewStateMachine("A")}
	sm.Configure("A").Permit("toB", "B").
		OnExit(func(ctx context.Context, i ...interface{}) error {
			addDeferRunner(ctx, func(ctx context.Context) {
				counter++
			})
			return nil
		})
	sm.Configure("B").Permit("toC", "C").
		OnEntry(func(ctx context.Context, i ...interface{}) error {
			return sm.FireCtx(ctx, "toC")
		}).
		OnExit(func(ctx context.Context, i ...interface{}) error {
			addDeferRunner(ctx, func(ctx context.Context) {
				counter++
			})
			return nil
		})
	assert.Equal(t, 0, counter)
	assert.NoError(t, sm.Fire("toB"))
	assert.Equal(t, "C", sm.MustState())
	assert.Equal(t, 2, counter) // error here 3 vs 2
}

but there is no api to get that is there any event pendding.

Can we provide a Firing() bool for StateMachine to indicate is StateMachine firing now?