Back to

Package fortress

Latest Go to latest

The highest tagged major version is .

Published: Sep 21, 2020 | License: AGPL-3.0 | Module:


Package fortress implements a convenient metaphor for an RWLock.

A "fortress" is constructed via a manifold's Start func, and accessed via its Output func as either a Guard or a Guest. To begin with, it's considered to be locked, and inaccessible to Guests; when the Guard Unlocks it, the Guests can Visit it until the Guard calls Lockdown. At that point, new Visits are blocked, and existing Visits are allowed to complete; the Lockdown returns once all Guests' Visits have completed.

The original motivating use case was for a component to mediate charm directory access between the uniter and the metrics collector. The metrics collector must be free to run its own independent hooks while the uniter is active; but metrics hooks and charm upgrades cannot be allowed to tread on one another's toes.



var ErrAborted = errors.New("fortress operation aborted")

ErrAborted is used to confirm clean termination of a blocking operation.

var ErrShutdown = errors.New("fortress worker shutting down")

ErrShutdown is used to report that the fortress worker is shutting down.

func IsFortressError

func IsFortressError(err error) bool

IsFortressError returns true if the error provided is fortress related.

func Manifold

func Manifold() dependency.Manifold

Manifold returns a dependency.Manifold that runs a fortress.

Clients should access the fortress resource via Guard and/or Guest pointers. Guest.Visit calls will block until a Guard.Unlock call is made; Guard.Lockdown calls will block new Guest.Visits and wait until all active Visits complete.

If multiple clients act as guards, the fortress' state at any time will be determined by whichever guard last ran an operation; that is to say, it will be impossible to reliably tell from outside. So please don't do that.

func Occupy

func Occupy(fortress Guest, start StartFunc, abort Abort) (worker.Worker, error)

Occupy launches a Visit to fortress that creates a worker and holds the visit open until the worker completes. Like most funcs that return any Worker, the caller takes responsibility for its lifetime; be aware that the responsibility is especially heavy here, because failure to clean up the worker will block cleanup of the fortress.

This may sound scary, but the alternative is to have multiple components "responsible for" a single worker's lifetime -- and Fortress itself would have to grow new concerns, of understanding and managing worker.Workers -- and that scenario ends up much worse.

type Abort

type Abort <-chan struct{}

Abort is a channel that can be closed to abort a blocking operation.

type Guard

type Guard interface {

	// Unlock unblocks all Guest.Visit calls.
	Unlock() error

	// Lockdown blocks new Guest.Visit calls, and waits for existing calls to
	// complete; it will return ErrAborted if the supplied Abort is closed
	// before lockdown is complete. In this situation, the fortress will
	// remain closed to new visits, but may still be executing pre-existing
	// ones; you need to wait for a Lockdown to complete successfully before
	// you can infer exclusive access.
	Lockdown(Abort) error

Guard manages Guest access to a fortress.

type Guest

type Guest interface {

	// Visit waits until the fortress is unlocked, then runs the supplied
	// Visit func. It will return ErrAborted if the supplied Abort is closed
	// before the Visit is started.
	Visit(Visit, Abort) error

Guest allows clients to Visit a fortress when it's unlocked; that is, to get non-exclusive access to whatever resource is being protected for the duration of the supplied Visit func.

type StartFunc

type StartFunc func() (worker.Worker, error)

StartFunc starts a worker.Worker.

type Visit

type Visit func() error

Visit is an operation that can be performed by a Guest.

Package Files

Documentation was rendered with GOOS=linux and GOARCH=amd64.

Jump to identifier

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to identifier