mirror of
https://github.com/TwiN/gatus.git
synced 2026-02-04 15:14:43 +00:00
fix: Don't panic on if there's 0 endpoints and >1 suite + update documentation (#1266)
This commit is contained in:
14
README.md
14
README.md
@@ -2771,24 +2771,24 @@ will send a `POST` request to `http://localhost:8080/playground` with the follow
|
|||||||
|
|
||||||
|
|
||||||
### Recommended interval
|
### Recommended interval
|
||||||
> 📝 This does not apply if `disable-monitoring-lock` is set to `true`, as the monitoring lock is what
|
To ensure that Gatus provides reliable and accurate results (i.e. response time), Gatus limits the number of
|
||||||
> tells Gatus to only evaluate one endpoint at a time.
|
endpoints/suites that can be evaluated at the same time.
|
||||||
|
In other words, even if you have multiple endpoints with the same interval, they are not guaranteed to run at the same time.
|
||||||
|
|
||||||
To ensure that Gatus provides reliable and accurate results (i.e. response time), Gatus only evaluates one endpoint at a time
|
The number of concurrent evaluations is determined by the `concurrency` configuration parameter, which defaults to `3`.
|
||||||
In other words, even if you have multiple endpoints with the same interval, they will not execute at the same time.
|
|
||||||
|
|
||||||
You can test this yourself by running Gatus with several endpoints configured with a very short, unrealistic interval,
|
You can test this yourself by running Gatus with several endpoints configured with a very short, unrealistic interval,
|
||||||
such as 1ms. You'll notice that the response time does not fluctuate - that is because while endpoints are evaluated on
|
such as 1ms. You'll notice that the response time does not fluctuate - that is because while endpoints are evaluated on
|
||||||
different goroutines, there's a global lock that prevents multiple endpoints from running at the same time.
|
different goroutines, there's a semaphore that controls how many endpoints/suites from running at the same time.
|
||||||
|
|
||||||
Unfortunately, there is a drawback. If you have a lot of endpoints, including some that are very slow or prone to timing out
|
Unfortunately, there is a drawback. If you have a lot of endpoints, including some that are very slow or prone to timing out
|
||||||
(the default timeout is 10s), then it means that for the entire duration of the request, no other endpoint can be evaluated.
|
(the default timeout is 10s), those slow evaluations may prevent other endpoints/suites from being evaluated.
|
||||||
|
|
||||||
The interval does not include the duration of the request itself, which means that if an endpoint has an interval of 30s
|
The interval does not include the duration of the request itself, which means that if an endpoint has an interval of 30s
|
||||||
and the request takes 2s to complete, the timestamp between two evaluations will be 32s, not 30s.
|
and the request takes 2s to complete, the timestamp between two evaluations will be 32s, not 30s.
|
||||||
|
|
||||||
While this does not prevent Gatus' from performing health checks on all other endpoints, it may cause Gatus to be unable
|
While this does not prevent Gatus' from performing health checks on all other endpoints, it may cause Gatus to be unable
|
||||||
to respect the configured interval, for instance:
|
to respect the configured interval, for instance, assuming `concurrency` is set to `1`:
|
||||||
- Endpoint A has an interval of 5s, and times out after 10s to complete
|
- Endpoint A has an interval of 5s, and times out after 10s to complete
|
||||||
- Endpoint B has an interval of 5s, and takes 1ms to complete
|
- Endpoint B has an interval of 5s, and takes 1ms to complete
|
||||||
- Endpoint B will be unable to run every 5s, because endpoint A's health evaluation takes longer than its interval
|
- Endpoint B will be unable to run every 5s, because endpoint A's health evaluation takes longer than its interval
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrNoEndpointInConfig is an error returned when a configuration file or directory has no endpoints configured
|
// ErrNoEndpointOrSuiteInConfig is an error returned when a configuration file or directory has no endpoints configured
|
||||||
ErrNoEndpointInConfig = errors.New("configuration should contain at least 1 endpoint")
|
ErrNoEndpointOrSuiteInConfig = errors.New("configuration should contain at least one endpoint or suite")
|
||||||
|
|
||||||
// ErrConfigFileNotFound is an error returned when a configuration file could not be found
|
// ErrConfigFileNotFound is an error returned when a configuration file could not be found
|
||||||
ErrConfigFileNotFound = errors.New("configuration file not found")
|
ErrConfigFileNotFound = errors.New("configuration file not found")
|
||||||
@@ -286,8 +286,8 @@ func parseAndValidateConfigBytes(yamlBytes []byte) (config *Config, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Check if the configuration file at least has endpoints configured
|
// Check if the configuration file at least has endpoints configured
|
||||||
if config == nil || config.Endpoints == nil || len(config.Endpoints) == 0 {
|
if config == nil || (len(config.Endpoints) == 0 && len(config.Suites) == 0) {
|
||||||
err = ErrNoEndpointInConfig
|
err = ErrNoEndpointOrSuiteInConfig
|
||||||
} else {
|
} else {
|
||||||
// XXX: Remove this in v6.0.0
|
// XXX: Remove this in v6.0.0
|
||||||
if config.Debug {
|
if config.Debug {
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ endpoints:
|
|||||||
pathAndFiles: map[string]string{
|
pathAndFiles: map[string]string{
|
||||||
"config.yaml": "",
|
"config.yaml": "",
|
||||||
},
|
},
|
||||||
expectedError: ErrNoEndpointInConfig,
|
expectedError: ErrNoEndpointOrSuiteInConfig,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "dir-with-two-config-files",
|
name: "dir-with-two-config-files",
|
||||||
@@ -737,8 +737,8 @@ badconfig:
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error("An error should've been returned")
|
t.Error("An error should've been returned")
|
||||||
}
|
}
|
||||||
if err != ErrNoEndpointInConfig {
|
if err != ErrNoEndpointOrSuiteInConfig {
|
||||||
t.Error("The error returned should have been of type ErrNoEndpointInConfig")
|
t.Error("The error returned should have been of type ErrNoEndpointOrSuiteInConfig")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1893,8 +1893,8 @@ endpoints:
|
|||||||
|
|
||||||
func TestParseAndValidateConfigBytesWithNoEndpoints(t *testing.T) {
|
func TestParseAndValidateConfigBytesWithNoEndpoints(t *testing.T) {
|
||||||
_, err := parseAndValidateConfigBytes([]byte(``))
|
_, err := parseAndValidateConfigBytes([]byte(``))
|
||||||
if !errors.Is(err, ErrNoEndpointInConfig) {
|
if !errors.Is(err, ErrNoEndpointOrSuiteInConfig) {
|
||||||
t.Error("The error returned should have been of type ErrNoEndpointInConfig")
|
t.Error("The error returned should have been of type ErrNoEndpointOrSuiteInConfig")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user