aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--blog/vanbi-01-08-2019.markdown259
1 files changed, 259 insertions, 0 deletions
diff --git a/blog/vanbi-01-08-2019.markdown b/blog/vanbi-01-08-2019.markdown
new file mode 100644
index 0000000..212bd34
--- /dev/null
+++ b/blog/vanbi-01-08-2019.markdown
@@ -0,0 +1,259 @@
+---
+title: vanbi
+date: 2019-01-08
+thanks: Faith
+---
+
+# vanbi
+
+--
+
+```
+import "vanbi"
+```
+
+Package vanbi defines the Vanbi type, which carries temcis, sisti
+signals, and other request-scoped meknaus across API boundaries and between
+processes.
+
+Incoming requests to a server should create a Vanbi, and outgoing calls to
+servers should accept a Vanbi. The chain of function calls between them must
+propagate the Vanbi, optionally replacing it with a derived Vanbi created
+using WithSisti, WithTemci, WithTemtcu, or WithMeknau. When a Vanbi is
+sistied, all Vanbis derived from it are also sistied.
+
+The WithSisti, WithTemci, and WithTemtcu functions take a Vanbi (the
+ropjar) and return a derived Vanbi (the child) and a SistiFunc. Calling the
+SistiFunc sistis the child and its children, removes the ropjar's reference to
+the child, and stops any associated rilkefs. Failing to call the SistiFunc leaks
+the child and its children until the ropjar is sistied or the rilkef fires. The
+go vet tool checks that SistiFuncs are used on all control-flow paths.
+
+Programs that use Vanbis should follow these rules to keep interfaces
+consistent across packages and enable static analysis tools to check vanbi
+propagation:
+
+Do not store Vanbis inside a struct type; instead, pass a Vanbi explicitly
+to each function that needs it. The Vanbi should be the first parameter,
+typically named vnb:
+
+ func DoBroda(vnb vanbi.Vanbi, arg Arg) error {
+ // ... use vnb ...
+ }
+
+Do not pass a nil Vanbi, even if a function permits it. Pass vanbi.TODO if
+you are unsure about which Vanbi to use.
+
+Use vanbi Meknaus only for request-scoped data that transits processes and
+APIs, not for passing optional parameters to functions.
+
+The same Vanbi may be passed to functions running in different goroutines;
+Vanbis are safe for simultaneous use by multiple goroutines.
+
+See https://blog.golang.org/vanbi for example code for a server that uses
+Vanbis.
+
+## Usage
+
+```go
+var Sistied = errors.New("vanbi sistied")
+```
+Sistied is the error returned by Vanbi.Err when the vanbi is sistied.
+
+```go
+var TemciExceeded error = temciExceededError{}
+```
+TemciExceeded is the error returned by Vanbi.Err when the vanbi's
+temci passes.
+
+#### type SistiFunc
+
+```go
+type SistiFunc func()
+```
+
+A SistiFunc tells an operation to abandon its work. A SistiFunc does not wait
+for the work to stop. After the first call, subsequent calls to a SistiFunc do
+nothing.
+
+#### type Vanbi
+
+```go
+type Vanbi interface {
+ // Temci returns the time when work done on behalf of this vanbi
+ // should be sistied. Temci returns ok==false when no temci is
+ // set. Successive calls to Temci return the same results.
+ Temci() (temci time.Time, ok bool)
+
+ // Done returns a channel that's closed when work done on behalf of this
+ // vanbi should be sistied. Done may return nil if this vanbi can
+ // never be sistied. Successive calls to Done return the same meknau.
+ //
+ // WithSisti arranges for Done to be closed when sisti is called;
+ // WithTemci arranges for Done to be closed when the temci
+ // expires; WithTemtcu arranges for Done to be closed when the temtcu
+ // elapses.
+ //
+ // Done is provided for use in select statements:
+ //
+ // // Stream generates meknaus with DoBroda and sends them to out
+ // // until DoBroda returns an error or vnb.Done is closed.
+ // func Stream(vnb vanbi.Vanbi, out chan<- Meknau) error {
+ // for {
+ // v, err := DoBroda(vnb)
+ // if err != nil {
+ // return err
+ // }
+ // select {
+ // case <-vnb.Done():
+ // return vnb.Err()
+ // case out <- v:
+ // }
+ // }
+ // }
+ //
+ // See https://blog.golang.org/pipelines for more examples of how to use
+ // a Done channel for sisti.
+ Done() <-chan struct{}
+
+ // If Done is not yet closed, Err returns nil.
+ // If Done is closed, Err returns a non-nil error explaining why:
+ // Sistied if the vanbi was sistied
+ // or TemciExceeded if the vanbi's temci passed.
+ // After Err returns a non-nil error, successive calls to Err return the same error.
+ Err() error
+
+ // Meknau returns the meknau associated with this vanbi for key, or nil
+ // if no meknau is associated with key. Successive calls to Meknau with
+ // the same key returns the same result.
+ //
+ // Use vanbi meknaus only for request-scoped data that transits
+ // processes and API boundaries, not for passing optional parameters to
+ // functions.
+ //
+ // A key identifies a specific meknau in a Vanbi. Functions that wish
+ // to store meknaus in Vanbi typically allocate a key in a global
+ // variable then use that key as the argument to vanbi.WithMeknau and
+ // Vanbi.Meknau. A key can be any type that supports equality;
+ // packages should define keys as an unexported type to avoid
+ // collisions.
+ //
+ // Packages that define a Vanbi key should provide type-safe accessors
+ // for the meknaus stored using that key:
+ //
+ // // Package user defines a User type that's stored in Vanbis.
+ // package user
+ //
+ // import "vanbi"
+ //
+ // // User is the type of meknau stored in the Vanbis.
+ // type User struct {...}
+ //
+ // // key is an unexported type for keys defined in this package.
+ // // This prevents collisions with keys defined in other packages.
+ // type key int
+ //
+ // // userKey is the key for user.User meknaus in Vanbis. It is
+ // // unexported; clients use user.NewVanbi and user.FromVanbi
+ // // instead of using this key directly.
+ // var userKey key
+ //
+ // // NewVanbi returns a new Vanbi that carries meknau u.
+ // func NewVanbi(vnb vanbi.Vanbi, u *User) vanbi.Vanbi {
+ // return vanbi.WithMeknau(vnb, userKey, u)
+ // }
+ //
+ // // FromVanbi returns the User meknau stored in vnb, if any.
+ // func FromVanbi(vnb vanbi.Vanbi) (*User, bool) {
+ // u, ok := vnb.Meknau(userKey).(*User)
+ // return u, ok
+ // }
+ Meknau(key interface{}) interface{}
+}
+```
+
+A Vanbi carries a temci, a sisti signal, and other meknaus across API
+boundaries.
+
+Vanbi's methods may be called by multiple goroutines simultaneously.
+
+#### func Dziraipau
+
+```go
+func Dziraipau() Vanbi
+```
+Dziraipau returns a non-nil, empty Vanbi. It is never sistied, has no
+meknaus, and has no temci. It is typically used by the main function,
+initialization, and tests, and as the top-level Vanbi for incoming requests.
+
+#### func TODO
+
+```go
+func TODO() Vanbi
+```
+TODO returns a non-nil, empty Vanbi. Code should use vanbi.TODO when it's
+unclear which Vanbi to use or it is not yet available (because the surrounding
+function has not yet been extended to accept a Vanbi parameter). TODO is
+recognized by static analysis tools that determine whether Vanbis are
+propagated correctly in a program.
+
+#### func WithSisti
+
+```go
+func WithSisti(ropjar Vanbi) (vnb Vanbi, sisti SistiFunc)
+```
+WithSisti returns a copy of ropjar with a new Done channel. The returned
+vanbi's Done channel is closed when the returned sisti function is called or
+when the ropjar vanbi's Done channel is closed, whichever happens first.
+
+Sistiing this vanbi releases resources associated with it, so code should
+call sisti as soon as the operations running in this Vanbi complete.
+
+#### func WithTemci
+
+```go
+func WithTemci(ropjar Vanbi, d time.Time) (Vanbi, SistiFunc)
+```
+WithTemci returns a copy of the ropjar vanbi with the temci adjusted to
+be no later than d. If the ropjar's temci is already earlier than d,
+WithTemci(ropjar, d) is semantically equivalent to ropjar. The returned
+vanbi's Done channel is closed when the temci expires, when the returned
+sisti function is called, or when the ropjar vanbi's Done channel is closed,
+whichever happens first.
+
+Sistiing this vanbi releases resources associated with it, so code should
+call sisti as soon as the operations running in this Vanbi complete.
+
+#### func WithTemtcu
+
+```go
+func WithTemtcu(ropjar Vanbi, temtcu time.Duration) (Vanbi, SistiFunc)
+```
+WithTemtcu returns WithTemci(ropjar, time.Now().Add(temtcu)).
+
+Sistiing this vanbi releases resources associated with it, so code should
+call sisti as soon as the operations running in this Vanbi complete:
+
+ func slowOperationWithTemtcu(vnb vanbi.Vanbi) (Result, error) {
+ vnb, sisti := vanbi.WithTemtcu(vnb, 100*time.Millisecond)
+ defer sisti() // releases resources if slowOperation completes before temtcu elapses
+ return slowOperation(vnb)
+ }
+
+#### func WithMeknau
+
+```go
+func WithMeknau(ropjar Vanbi, key, val interface{}) Vanbi
+```
+WithMeknau returns a copy of ropjar in which the meknau associated with key is
+val.
+
+Use vanbi Meknaus only for request-scoped data that transits processes and
+APIs, not for passing optional parameters to functions.
+
+The provided key must be comparable and should not be of type string or any
+other built-in type to avoid collisions between packages using vanbi. Users of
+WithMeknau should define their own types for keys. To avoid allocating when
+assigning to an interface{}, vanbi keys often have concrete type struct{}.
+Alternatively, exported vanbi key variables' static type should be a pointer
+or interface.