Context-Scoped Sessions
- Dominant language
- Go
- Stars
- 17.1k
- Forks
- 3.2k
- Avg merge
- 3d 18h
- Merged PRs (30d)
- 11
Description
Currently, bitswap sessions are hard to work with because we need to:
1. Create a new session.
2. Pass this session to all services that need access to the exchange.
Usually 2 involves _re-creating_ these services. This can be very painful and we have many places in go-ipfs where we simply aren't doing this.
Instead, we should associate a session with a _context_. That way, whenever we use the context, we use the session. When we cancel the context, we cancel the session.
## PRs
* [ ] https://github.com/ipfs/go-ipfs-exchange-interface/pull/9
* [ ] https://github.com/ipfs/go-bitswap/pull/401
* [ ] https://github.com/ipfs/go-merkledag/pull/55
* [ ] https://github.com/ipfs/go-ipfs/pull/7201
## Design
Store a session "key" in the session to identify the session.
```go
// SessionID is an opaque type uniquely identifying a session.
type SessionID struct {
// Opaque type to ensure users don't cook this up and break things.
// Sequentially and atomically allocated.
id uint64
}
// IsZero returns true if this SessionId is the zero value (not a valid session
// ID).
func (id SessionID) IsZero() bool {
return id.id == 0
}
// NewSession registers a new session with the context. The session will be
// closed when the passed-in context is canceled.
//
// If there's already a session associated with the context, the existing
// session will be used.
//
// This function does not initialize any state, it just reserves a new SessionID
// associates it with the context.
func NewSession(ctx context.Context) context.Context {
...
}
// GetOrCreateSession loads the session from the context, or creates one if
// there is no associated session.
//
// This function also returns the context used to create the session. The
// session should be stopped when this context is canceled.
func GetOrCreateSession(ctx context.Context) (SessionID, context.Context) {
...
}
```
## Alternatives
I've considered two alternatives:
1. Store the exchange/fetcher in the context.
2. Store an abstract session in the context.
### Embedded Exchange
We could:
1. Create a session.
2. Store the session/"fetcher" in the context.
3. Use this session inside the blockservice instead of the actual exchange.
On one hand, this is nice because we can embed alternative exchanges for a specific request. For example, we could embed an _offline_ exchange to perform an offline lookup.
On the other hand:
1. This is spooky action at a distance.
2. This _only_ solves this particular problem and doesn't help services exchange information related to sessions.
### Abstract Session
We could also store an abstract session object in the context (https://github.com/ipfs/go-ipfs/issues/6525). However, this would require building a general-purpose, abstract session/state manager. The session-key design lets us do everything the abstract session proposal does, _without_ requiring a general-purpose anything.
Contributor guide
Assessment
This issue has not been assessed yet.