-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(kaze/controllers): Implement Server sent events at regular speci… #187
Conversation
time.Sleep(2 * configs.ServiceConfig.Mizu.MetricsInterval) | ||
}() | ||
c.Stream(func(w io.Writer) bool { | ||
if _, ok := <-chanStream; ok { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is the chanStream
part necessary?
You can just include the time.Sleep
part in this function itself
go func() { | ||
defer close(chanStream) | ||
chanStream <- true | ||
time.Sleep(2 * configs.ServiceConfig.Mizu.MetricsInterval) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the 2 *
part is not required
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 * part was due to you reply to the question I asked in slack for time interval between two Server Sent events
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad, it should be just configs.ServiceConfig.Mizu.MetricsInterval
c.SSEvent("metrics", metrics) | ||
return true | ||
} | ||
return false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the overall function will be simply
c.Stream(func(w io.Writer) bool {
metrics := mongo.FetchContainerMetrics(types.M{
mongo.NameKey: appName,
mongo.TimestampKey: types.M{
"$gte": time.Now().Unix() - configs.ServiceConfig.Mizu.MetricsInterval * time.Second,
},
})
c.SSEvent("metrics", metrics)
time.Sleep(configs.ServiceConfig.Mizu.MetricsInterval * time.Second)
return true
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is using a channel any different than the above function ^ ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, as was discussed over slack, there was unknown i/o timeout
error. I still am not sure about the exact reason but here what I infer from the success:
- The original
time.Sleep()
was forcing the stream to halt somehow, but SSEvent was not prepared for discrete streams. - So by using this channel mutex triggered SSEvent, it is suppressed during the halt duration. And hence no timeout errors. I tried to mimic some of the errors by manipulating the goroutine and this inference feels rational.
- gin's SSEvent implementation is buggy and we might need a replacement later.
After doing the requested changes test your feature using this example https://www.w3schools.com/html/html5_serversentevents.asp Also keep a track of the requests in the network tab |
"$gte": time.Now().Unix() - timeSpan, | ||
}, | ||
}) | ||
count, _ := strconv.ParseInt(metricsCount, 10, 64) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to check for error handling here. If someone sends a string "meow" in the "fetch_count" query param then the above line will throw an error
}, | ||
}, count) | ||
c.SSEvent("metrics", metrics) | ||
fetchInt, _ := strconv.ParseInt(metricsFetchInterval, 10, 64) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check for error handling here too in case "metricsFetchInterval" is a string like "meow"
metricsFetchInterval := c.Query("fetch_interval") | ||
metricsCount := c.Query("fetch_count") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case these query params are not set, you should have some default values in place.
Also, fix your commit message as per the |
cf9cd4f
to
3b8a764
Compare
if fetchIntTime < configs.ServiceConfig.Mizu.MetricsInterval { | ||
fetchIntTime = 2 * fetchIntTime | ||
} | ||
time.Sleep(configs.ServiceConfig.Mizu.MetricsInterval * time.Second * fetchIntTime) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it necessary to multiply configs.ServiceConfig.Mizu.MetricsInterval
and fetchIntTime
in this context ?
if fetchIntTime < configs.ServiceConfig.Mizu.MetricsInterval { | ||
fetchIntTime = 2 * fetchIntTime |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should check for this condition outside c.Stream
.
Also to retain safety you can change fetchIntTime = 2 * fetchIntTime
to fetchIntTime = 2 * configs.ServiceConfig.Mizu.MetricsInterval
metricsFetchInterval := c.Query("fetch_interval") | ||
fetchInt, err := strconv.ParseInt(metricsFetchInterval, 10, 64) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the line metricsFetchInterval := c.Query("fetch_interval")
is unnecessary
You can just do fetchInt, err := strconv.ParseInt(c.Query("fetch_interval"), 10, 64)
Doing this might prevent an extra register being used unnecessarily in case the compiler's assembly optimization was not good enough
Same for the "fetch_counts" part
@@ -228,29 +230,36 @@ func TransferApplicationOwnership(c *gin.Context) { | |||
|
|||
// FetchMetrics retrieves the metrics of an application's container | |||
func FetchMetrics(c *gin.Context) { | |||
c.Writer.Header().Set("Content-Type", "text/event-stream") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this line is unnecessary as the response headers are automatically set during c.SSEvent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@supra08 fix this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Also you can rename "fetch_interval" and "fetch_count" to just "interval" and "count" respectively. That way it is more readable and easier to use from the perspective of an API user. |
c.AbortWithStatusJSON(400, gin.H{ | ||
"success": false, | ||
"error": "App name not provided for metrics", | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a return statement is required after this to terminate the function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also you can leave the check of appName == ""
.
This is already handled by the IsAppOwner
middleware. You cannot create an app with an empty string as name. This rule is already enforced.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@supra08 remove the check for appName == ""
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -228,29 +230,36 @@ func TransferApplicationOwnership(c *gin.Context) { | |||
|
|||
// FetchMetrics retrieves the metrics of an application's container | |||
func FetchMetrics(c *gin.Context) { | |||
c.Writer.Header().Set("Content-Type", "text/event-stream") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@supra08 fix this
c.AbortWithStatusJSON(400, gin.H{ | ||
"success": false, | ||
"error": "App name not provided for metrics", | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@supra08 remove the check for appName == ""
c.SSEvent("metrics", metrics) | ||
return true | ||
} | ||
return false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is using a channel any different than the above function ^ ?
…fied period for metrics
…and fallback default values
…metrics in container unavailability
…le broken streams
… checks and headers
…to provide static time series data
Codecov Report
|
…fied period for metrics