<commit_before>package circuitbreaker

import (
	"errors"
	"time"
)

type CircuitBreaker struct {
	Timeout       int
	Threshold     int
	ResetTimeout  time.Duration
	BreakerOpen   func(*CircuitBreaker, error)
	BreakerClosed func(*CircuitBreaker)
	failures      int
	lastFailure   time.Time
	halfOpenGate  int
	halfOpens     int
}

type circuit func() error
type state int

const (
	open      state = iota
	half_open state = iota
	closed    state = iota
)

var (
	BreakerOpen    = errors.New("breaker open")
	BreakerTimeout = errors.New("breaker timeout")
)

func NewCircuitBreaker(threshold int) *CircuitBreaker {
	return NewTimeoutCircuitBreaker(0, threshold)
}

func NewTimeoutCircuitBreaker(timeout, threshold int) *CircuitBreaker {
	return &CircuitBreaker{
		Timeout:      timeout,
		Threshold:    threshold,
		ResetTimeout: time.Millisecond * 500}
}

func (cb *CircuitBreaker) Call(circuit circuit) error {
	state := cb.state()

	if state == open {
		return BreakerOpen
	}

	var err error
	if cb.Timeout > 0 {
		err = cb.callWithTimeout(circuit)
	} else {
		err = circuit()
	}

	if err != nil {
		if state == half_open {
			cb.halfOpens = 0
		}
		cb.failures += 1
		cb.lastFailure = time.Now()

		if cb.BreakerOpen != nil && cb.failures == cb.Threshold {
			cb.BreakerOpen(cb, err)
		}
		return err
	}

	if cb.BreakerClosed != nil && cb.failures > 0 {
		cb.BreakerClosed(cb)
	}

	cb.failures = 0
	cb.halfOpens = 0
	return nil
}

func (cb *CircuitBreaker) callWithTimeout(circuit circuit) error {
	c := make(chan int, 1)
	var err error
	go func() {
		err = circuit()
		close(c)
	}()
	select {
	case <-c:
		return err
	case <-time.After(time.Second * time.Duration(cb.Timeout)):
		return BreakerTimeout
	}
}

func (cb *CircuitBreaker) state() state {
	if cb.failures >= cb.Threshold {
		since := time.Since(cb.lastFailure)
		if since > cb.ResetTimeout {
			if cb.halfOpens <= cb.halfOpenGate {<commit_msg>didn't really need that<commit_after>package circuitbreaker

import (
	"errors"
	"time"
)

type CircuitBreaker struct {
	Timeout       int
	Threshold     int
	ResetTimeout  time.Duration
	BreakerOpen   func(*CircuitBreaker, error)
	BreakerClosed func(*CircuitBreaker)
	failures      int
	lastFailure   time.Time
	halfOpens     int
}

type circuit func() error
type state int

const (
	open      state = iota
	half_open state = iota
	closed    state = iota
)

var (
	BreakerOpen    = errors.New("breaker open")
	BreakerTimeout = errors.New("breaker timeout")
)

func NewCircuitBreaker(threshold int) *CircuitBreaker {
	return NewTimeoutCircuitBreaker(0, threshold)
}

func NewTimeoutCircuitBreaker(timeout, threshold int) *CircuitBreaker {
	return &CircuitBreaker{
		Timeout:      timeout,
		Threshold:    threshold,
		ResetTimeout: time.Millisecond * 500}
}

func (cb *CircuitBreaker) Call(circuit circuit) error {
	state := cb.state()

	if state == open {
		return BreakerOpen
	}

	var err error
	if cb.Timeout > 0 {
		err = cb.callWithTimeout(circuit)
	} else {
		err = circuit()
	}

	if err != nil {
		if state == half_open {
			cb.halfOpens = 0
		}
		cb.failures += 1
		cb.lastFailure = time.Now()

		if cb.BreakerOpen != nil && cb.failures == cb.Threshold {
			cb.BreakerOpen(cb, err)
		}
		return err
	}

	if cb.BreakerClosed != nil && cb.failures > 0 {
		cb.BreakerClosed(cb)
	}

	cb.failures = 0
	cb.halfOpens = 0
	return nil
}

func (cb *CircuitBreaker) callWithTimeout(circuit circuit) error {
	c := make(chan int, 1)
	var err error
	go func() {
		err = circuit()
		close(c)
	}()
	select {
	case <-c:
		return err
	case <-time.After(time.Second * time.Duration(cb.Timeout)):
		return BreakerTimeout
	}
}

func (cb *CircuitBreaker) state() state {
	if cb.failures >= cb.Threshold {
		since := time.Since(cb.lastFailure)
		if since > cb.ResetTimeout {
			if cb.halfOpens == 0 {
{'fraction_non_alphanumeric': 0.10967571842868441, 'fraction_numerical': 0.006063801740047456, 'mean_word_length': 3.4687868080094226, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3050944', 'n_tokens_mistral': 1467, 'n_tokens_neox': 1333, 'n_words': 347}