Fix unstoppable kubewatcher (#208)
Fix a bug due to which watches could never be stopped; simplify control flow a bit.
This commit is contained in:
committed by
Soam Vasani
parent
51c84f3cfc
commit
46ff55ab49
+62
-41
@@ -191,8 +191,7 @@ func (kw *KubeWatcher) removeWatch(w *fission.Watch) error {
|
|||||||
fmt.Sprintf("watch doesn't exist: %v", w.Metadata))
|
fmt.Sprintf("watch doesn't exist: %v", w.Metadata))
|
||||||
}
|
}
|
||||||
delete(kw.watches, w.Metadata.Uid)
|
delete(kw.watches, w.Metadata.Uid)
|
||||||
atomic.StoreInt32(ws.stopped, 1)
|
ws.stop()
|
||||||
ws.kubeWatch.Stop()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,50 +261,72 @@ func getResourceVersion(obj runtime.Object) (string, error) {
|
|||||||
func (ws *watchSubscription) eventDispatchLoop() {
|
func (ws *watchSubscription) eventDispatchLoop() {
|
||||||
log.Println("Listening to watch ", ws.Watch.Metadata.Name)
|
log.Println("Listening to watch ", ws.Watch.Metadata.Name)
|
||||||
for {
|
for {
|
||||||
for {
|
// check watchSubscription is stopped or not before waiting for event
|
||||||
ev, more := <-ws.kubeWatch.ResultChan()
|
// comes from the kubeWatch.ResultChan(). This fix the edge case that
|
||||||
if !more {
|
// new kubewatch is created in the restartWatch() while the old kubewatch
|
||||||
log.Println("Watch stopped", ws.Watch.Metadata.Name)
|
// is being used in watchSubscription.stop().
|
||||||
break
|
if ws.isStopped() {
|
||||||
}
|
break
|
||||||
if ev.Type == watch.Error {
|
|
||||||
e := apierrs.FromObject(ev.Object)
|
|
||||||
log.Println("Watch error, retrying in a second: %v", e)
|
|
||||||
// Start from the beginning to get around "too old resource version"
|
|
||||||
ws.lastResourceVersion = ""
|
|
||||||
time.Sleep(time.Second)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
rv, err := getResourceVersion(ev.Object)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error getting resourceVersion from object: %v", err)
|
|
||||||
} else {
|
|
||||||
log.Printf("rv=%v", rv)
|
|
||||||
ws.lastResourceVersion = rv
|
|
||||||
}
|
|
||||||
|
|
||||||
// Serialize the object
|
|
||||||
var buf bytes.Buffer
|
|
||||||
err = printKubernetesObject(ev.Object, &buf)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Failed to serialize object: %v", err)
|
|
||||||
// TODO send a POST request indicating error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Event and object type aren't in the serialized object
|
|
||||||
headers := map[string]string{
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"X-Kubernetes-Event-Type": string(ev.Type),
|
|
||||||
"X-Kubernetes-Object-Type": reflect.TypeOf(ev.Object).Elem().Name(),
|
|
||||||
}
|
|
||||||
// Event and object type aren't in the serialized object
|
|
||||||
ws.publisher.Publish(buf.String(), headers, ws.Watch.Target)
|
|
||||||
}
|
}
|
||||||
if atomic.LoadInt32(ws.stopped) == 0 {
|
ev, more := <-ws.kubeWatch.ResultChan()
|
||||||
|
if !more {
|
||||||
|
if ws.isStopped() {
|
||||||
|
// watch is removed by user.
|
||||||
|
log.Println("Watch stopped", ws.Watch.Metadata.Name)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
// watch closed due to timeout, restart it.
|
||||||
|
log.Printf("Watch %v timed out, restarting", ws.Watch.Metadata.Name)
|
||||||
|
err := ws.restartWatch()
|
||||||
|
if err != nil {
|
||||||
|
log.Panicf("Failed to restart watch: %v", err)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ev.Type == watch.Error {
|
||||||
|
e := apierrs.FromObject(ev.Object)
|
||||||
|
log.Println("Watch error, retrying in a second: %v", e)
|
||||||
|
// Start from the beginning to get around "too old resource version"
|
||||||
|
ws.lastResourceVersion = ""
|
||||||
|
time.Sleep(time.Second)
|
||||||
err := ws.restartWatch()
|
err := ws.restartWatch()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panicf("Failed to restart watch: %v", err)
|
log.Panicf("Failed to restart watch: %v", err)
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
rv, err := getResourceVersion(ev.Object)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error getting resourceVersion from object: %v", err)
|
||||||
|
} else {
|
||||||
|
ws.lastResourceVersion = rv
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize the object
|
||||||
|
var buf bytes.Buffer
|
||||||
|
err = printKubernetesObject(ev.Object, &buf)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to serialize object: %v", err)
|
||||||
|
// TODO send a POST request indicating error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event and object type aren't in the serialized object
|
||||||
|
headers := map[string]string{
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-Kubernetes-Event-Type": string(ev.Type),
|
||||||
|
"X-Kubernetes-Object-Type": reflect.TypeOf(ev.Object).Elem().Name(),
|
||||||
|
}
|
||||||
|
ws.publisher.Publish(buf.String(), headers, ws.Watch.Target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ws *watchSubscription) stop() {
|
||||||
|
atomic.StoreInt32(ws.stopped, 1)
|
||||||
|
ws.kubeWatch.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ws *watchSubscription) isStopped() bool {
|
||||||
|
return atomic.LoadInt32(ws.stopped) == 1
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user