When the server is forwarding objects to the subscriber, if the subscriber disconnects willingly by calling session.conn.close() or the connection is interrupted by page reload, which causes the connection to disconnect, the server crashes with the same error:
Server log when subscriber disconnects gracefully
```go
...
(log prefix with variation in time: time=2024-10-08T14:41:47.542+02:00 level=INFO source=/Users/usr/go/pkg/mod/github.com/mengelbart/moqtransport@v0.3.1-0.20240715134205-0c18f3a3b439/)
remote_track.go:64 msg="reading object stream"
remote_track.go:70 msg="finished reading object stream"
session.go:245 msg="failed to accept uni stream" MOQ_SESSION_SERVER.error=""
session.go:580 msg="peerClosed called"
control_stream.go:61 msg="close called, leaving control stream write loop"
control_stream.go:47 msg=TODO MOQ_CONTROL_STREAM.error="stream reset, but failed to convert stream error 386759528: error code outside of expected range"
remote_track.go:56 msg="push object" MOQ_REMOTE_TRACK.groupId=11 MOQ_REMOTE_TRACK.objectId=5 "MOQ_REMOTE_TRACK.payload size in bytes"=53
remote_track.go:64 msg="reading object stream"
send_subscription.go:68 msg="sending object" MOQ_SEND_SUBSCRIPTION.namespace=ninja MOQ_SEND_SUBSCRIPTION.trackname=audio MOQ_SEND_SUBSCRIPTION.group-id=11 MOQ_SEND_SUBSCRIPTION.object-id=5
panic:
goroutine 3037 [running]:
github.com/mengelbart/moqtransport.(*sendSubscription).sendObject(0x14000218750, {0xb, 0x5, 0x0, 0x1, {0x1400056c800, 0x35, 0x35}})
/Users/usr/go/pkg/mod/github.com/mengelbart/moqtransport@v0.3.1-0.20240715134205-0c18f3a3b439/send_subscription.go:76 +0x1e8
github.com/mengelbart/moqtransport.(*sendSubscription).loop(0x14000218750)
/Users/usr/go/pkg/mod/github.com/mengelbart/moqtransport@v0.3.1-0.20240715134205-0c18f3a3b439/send_subscription.go:60 +0x9c
created by github.com/mengelbart/moqtransport.newSendSubscription in goroutine 2231
/Users/usr/go/pkg/mod/github.com/mengelbart/moqtransport@v0.3.1-0.20240715134205-0c18f3a3b439/send_subscription.go:51 +0x278
exit status 2
```
Server log when subscriber disconnects interuptly
```go
...
(log prefix with variation in time: time=2024-10-08T14:47:02.221+02:00 level=INFO source=/Users/usr/go/pkg/mod/github.com/mengelbart/moqtransport@v0.3.1-0.20240715134205-0c18f3a3b439/)
remote_track.go:64 msg="reading object stream"
remote_track.go:70 msg="finished reading object stream"
remote_track.go:56 msg="push object" MOQ_REMOTE_TRACK.groupId=44 MOQ_REMOTE_TRACK.objectId=101 "MOQ_REMOTE_TRACK.payload size in bytes"=14754
remote_track.go:64 msg="reading object stream"
remote_track.go:70 msg="finished reading object stream"
remote_track.go:56 msg="push object" MOQ_REMOTE_TRACK.groupId=44 MOQ_REMOTE_TRACK.objectId=103 "MOQ_REMOTE_TRACK.payload size in bytes"=6087
remote_track.go:64 msg="reading object stream"
remote_track.go:70 msg="finished reading object stream"
remote_track.go:56 msg="push object" MOQ_REMOTE_TRACK.groupId=10 MOQ_REMOTE_TRACK.objectId=95 "MOQ_REMOTE_TRACK.payload size in bytes"=40
remote_track.go:64 msg="reading object stream"
send_subscription.go:68 msg="sending object" MOQ_SEND_SUBSCRIPTION.namespace=ninja MOQ_SEND_SUBSCRIPTION.trackname=audio MOQ_SEND_SUBSCRIPTION.group-id=10 MOQ_SEND_SUBSCRIPTION.object-id=95
remote_track.go:70 msg="finished reading object stream"
panic: too many open streams
goroutine 2599 [running]:
github.com/mengelbart/moqtransport.(*sendSubscription).sendObject(0x1400028c870, {0xa, 0x5f, 0x0, 0x1, {0x14000408210, 0x28, 0x28}})
/Users/usr/go/pkg/mod/github.com/mengelbart/moqtransport@v0.3.1-0.20240715134205-0c18f3a3b439/send_subscription.go:76 +0x1e8
github.com/mengelbart/moqtransport.(*sendSubscription).loop(0x1400028c870)
/Users/usr/go/pkg/mod/github.com/mengelbart/moqtransport@v0.3.1-0.20240715134205-0c18f3a3b439/send_subscription.go:60 +0x9c
created by github.com/mengelbart/moqtransport.newSendSubscription in goroutine 1982
/Users/usr/go/pkg/mod/github.com/mengelbart/moqtransport@v0.3.1-0.20240715134205-0c18f3a3b439/send_subscription.go:51 +0x278
exit status 2
```
Both logs point to the same cause that traces back to Line 76:
send_subscription.go
```go
//send_subscription.go
func newSendSubscription(conn Connection, subscribeID, trackAlias uint64, namespace, trackname string) *sendSubscription {
ctx, cancelCtx := context.WithCancel(context.Background())
sub := &sendSubscription{
logger: defaultLogger.WithGroup("MOQ_SEND_SUBSCRIPTION").With(
"namespace", namespace,
"trackname", trackname,
),
cancelCtx: cancelCtx,
cancelWG: sync.WaitGroup{},
ctx: ctx,
subscriptionIDinTrack: -1,
subscribeID: subscribeID,
trackAlias: trackAlias,
namespace: namespace,
trackname: trackname,
conn: conn,
objectCh: make(chan Object, 1024),
trackHeaderStream: nil,
groupHeaderStreams: map[uint64]*groupHeaderStream{},
}
sub.cancelWG.Add(1)
go sub.loop() //#L51
return sub
}
func (s *sendSubscription) loop() {
defer s.cancelWG.Done()
for {
select {
case o := <-s.objectCh:
s.sendObject(o) //#L60
case <-s.ctx.Done():
return
}
}
}
func (s *sendSubscription) sendObject(o Object) {
s.logger.Info("sending object", "group-id", o.GroupID, "object-id", o.ObjectID)
switch o.ForwardingPreference {
case ObjectForwardingPreferenceDatagram:
if err := s.sendDatagram(o); err != nil {
panic(err)
}
case ObjectForwardingPreferenceStream:
if err := s.sendObjectStream(o); err != nil {
panic(err) // #L76
}
case ObjectForwardingPreferenceStreamGroup:
if err := s.sendGroupHeaderStream(o); err != nil {
panic(err)
}
case ObjectForwardingPreferenceStreamTrack:
if err := s.sendTrackHeaderStream(o); err != nil {
panic(err)
}
}
}
```
We need to handle disconnection gracefully such as logging the err or do sth else, instead of panic(err).
When the server is forwarding objects to the subscriber, if the subscriber disconnects willingly by calling
session.conn.close()
or the connection is interrupted by page reload, which causes the connection to disconnect, the server crashes with the same error:Server log when subscriber disconnects gracefully
```go ... (log prefix with variation in time: time=2024-10-08T14:41:47.542+02:00 level=INFO source=/Users/usr/go/pkg/mod/github.com/mengelbart/moqtransport@v0.3.1-0.20240715134205-0c18f3a3b439/) remote_track.go:64 msg="reading object stream" remote_track.go:70 msg="finished reading object stream" session.go:245 msg="failed to accept uni stream" MOQ_SESSION_SERVER.error="" session.go:580 msg="peerClosed called" control_stream.go:61 msg="close called, leaving control stream write loop" control_stream.go:47 msg=TODO MOQ_CONTROL_STREAM.error="stream reset, but failed to convert stream error 386759528: error code outside of expected range" remote_track.go:56 msg="push object" MOQ_REMOTE_TRACK.groupId=11 MOQ_REMOTE_TRACK.objectId=5 "MOQ_REMOTE_TRACK.payload size in bytes"=53 remote_track.go:64 msg="reading object stream" send_subscription.go:68 msg="sending object" MOQ_SEND_SUBSCRIPTION.namespace=ninja MOQ_SEND_SUBSCRIPTION.trackname=audio MOQ_SEND_SUBSCRIPTION.group-id=11 MOQ_SEND_SUBSCRIPTION.object-id=5 panic: goroutine 3037 [running]: github.com/mengelbart/moqtransport.(*sendSubscription).sendObject(0x14000218750, {0xb, 0x5, 0x0, 0x1, {0x1400056c800, 0x35, 0x35}}) /Users/usr/go/pkg/mod/github.com/mengelbart/moqtransport@v0.3.1-0.20240715134205-0c18f3a3b439/send_subscription.go:76 +0x1e8 github.com/mengelbart/moqtransport.(*sendSubscription).loop(0x14000218750) /Users/usr/go/pkg/mod/github.com/mengelbart/moqtransport@v0.3.1-0.20240715134205-0c18f3a3b439/send_subscription.go:60 +0x9c created by github.com/mengelbart/moqtransport.newSendSubscription in goroutine 2231 /Users/usr/go/pkg/mod/github.com/mengelbart/moqtransport@v0.3.1-0.20240715134205-0c18f3a3b439/send_subscription.go:51 +0x278 exit status 2 ```Server log when subscriber disconnects interuptly
```go ... (log prefix with variation in time: time=2024-10-08T14:47:02.221+02:00 level=INFO source=/Users/usr/go/pkg/mod/github.com/mengelbart/moqtransport@v0.3.1-0.20240715134205-0c18f3a3b439/) remote_track.go:64 msg="reading object stream" remote_track.go:70 msg="finished reading object stream" remote_track.go:56 msg="push object" MOQ_REMOTE_TRACK.groupId=44 MOQ_REMOTE_TRACK.objectId=101 "MOQ_REMOTE_TRACK.payload size in bytes"=14754 remote_track.go:64 msg="reading object stream" remote_track.go:70 msg="finished reading object stream" remote_track.go:56 msg="push object" MOQ_REMOTE_TRACK.groupId=44 MOQ_REMOTE_TRACK.objectId=103 "MOQ_REMOTE_TRACK.payload size in bytes"=6087 remote_track.go:64 msg="reading object stream" remote_track.go:70 msg="finished reading object stream" remote_track.go:56 msg="push object" MOQ_REMOTE_TRACK.groupId=10 MOQ_REMOTE_TRACK.objectId=95 "MOQ_REMOTE_TRACK.payload size in bytes"=40 remote_track.go:64 msg="reading object stream" send_subscription.go:68 msg="sending object" MOQ_SEND_SUBSCRIPTION.namespace=ninja MOQ_SEND_SUBSCRIPTION.trackname=audio MOQ_SEND_SUBSCRIPTION.group-id=10 MOQ_SEND_SUBSCRIPTION.object-id=95 remote_track.go:70 msg="finished reading object stream" panic: too many open streams goroutine 2599 [running]: github.com/mengelbart/moqtransport.(*sendSubscription).sendObject(0x1400028c870, {0xa, 0x5f, 0x0, 0x1, {0x14000408210, 0x28, 0x28}}) /Users/usr/go/pkg/mod/github.com/mengelbart/moqtransport@v0.3.1-0.20240715134205-0c18f3a3b439/send_subscription.go:76 +0x1e8 github.com/mengelbart/moqtransport.(*sendSubscription).loop(0x1400028c870) /Users/usr/go/pkg/mod/github.com/mengelbart/moqtransport@v0.3.1-0.20240715134205-0c18f3a3b439/send_subscription.go:60 +0x9c created by github.com/mengelbart/moqtransport.newSendSubscription in goroutine 1982 /Users/usr/go/pkg/mod/github.com/mengelbart/moqtransport@v0.3.1-0.20240715134205-0c18f3a3b439/send_subscription.go:51 +0x278 exit status 2 ```Both logs point to the same cause that traces back to Line 76:
send_subscription.go
```go //send_subscription.go func newSendSubscription(conn Connection, subscribeID, trackAlias uint64, namespace, trackname string) *sendSubscription { ctx, cancelCtx := context.WithCancel(context.Background()) sub := &sendSubscription{ logger: defaultLogger.WithGroup("MOQ_SEND_SUBSCRIPTION").With( "namespace", namespace, "trackname", trackname, ), cancelCtx: cancelCtx, cancelWG: sync.WaitGroup{}, ctx: ctx, subscriptionIDinTrack: -1, subscribeID: subscribeID, trackAlias: trackAlias, namespace: namespace, trackname: trackname, conn: conn, objectCh: make(chan Object, 1024), trackHeaderStream: nil, groupHeaderStreams: map[uint64]*groupHeaderStream{}, } sub.cancelWG.Add(1) go sub.loop() //#L51 return sub } func (s *sendSubscription) loop() { defer s.cancelWG.Done() for { select { case o := <-s.objectCh: s.sendObject(o) //#L60 case <-s.ctx.Done(): return } } } func (s *sendSubscription) sendObject(o Object) { s.logger.Info("sending object", "group-id", o.GroupID, "object-id", o.ObjectID) switch o.ForwardingPreference { case ObjectForwardingPreferenceDatagram: if err := s.sendDatagram(o); err != nil { panic(err) } case ObjectForwardingPreferenceStream: if err := s.sendObjectStream(o); err != nil { panic(err) // #L76 } case ObjectForwardingPreferenceStreamGroup: if err := s.sendGroupHeaderStream(o); err != nil { panic(err) } case ObjectForwardingPreferenceStreamTrack: if err := s.sendTrackHeaderStream(o); err != nil { panic(err) } } } ```We need to handle disconnection gracefully such as logging the err or do sth else, instead of
panic(err)
.