Documentation ¶
Index ¶
- Variables
- func AlertOnFailure(l *Locker) error
- func AlertOnOverwrite(l *Locker) error
- func DefaultQueue(queue string) func(*Locker) error
- func Host(host string) func(*Locker) error
- func LeaseDuration(duration time.Duration) func(*Locker) error
- func LeaseTimeout(duration time.Duration) func(*Locker) error
- func LogVerbose(l *Locker) error
- func MaxRetries(retries int) func(*Locker) error
- func QueueFromContext(c context.Context) (string, bool)
- func WithQueue(c context.Context, queue string) context.Context
- type EntityFactory
- type Error
- type Lock
- type Lockable
- type Locker
- func (l *Locker) Aquire(c context.Context, key *datastore.Key, entity Lockable, sequence int) error
- func (l *Locker) Complete(c context.Context, key *datastore.Key, entity Lockable) error
- func (l *Locker) Handle(handler TaskHandler, factory EntityFactory) http.Handler
- func (l *Locker) NewTask(key *datastore.Key, entity Lockable, path string, params url.Values) *taskqueue.Task
- func (l *Locker) Parse(c context.Context, r *http.Request) (*datastore.Key, int, error)
- func (l *Locker) Schedule(c context.Context, key *datastore.Key, entity Lockable, path string, ...) error
- type Option
- type TaskHandler
Constants ¶
This section is empty.
Variables ¶
var ( // ErrLockFailed signals that a lock attempt failed and the task trying to // aquire it should be retried. Using ServiceUnavailable (503) causes a task // retry without flooding the logs with visible errors. ErrLockFailed = Error{http.StatusServiceUnavailable, "lock failed (retry)"} // ErrTaskExpired signals that the task's sequence no is behind the sequence // stored on the entity. This means processing has already moved on and this // task should be dropped. This is likely caused by a spurious task re-execution. // Using OK (200) causes a task to be marked as successful so it won't be retried. ErrTaskExpired = Error{http.StatusOK, "task expired (abandon)"} // ErrTaskFailed signals that the task has failed permanently (tried more than // the MaxRetries allowed) so should be abandoned. // Using OK (200) causes a task to be marked as successful so it won't be retried. ErrTaskFailed = Error{http.StatusOK, "task failed permanently (abandon)"} )
Functions ¶
func AlertOnFailure ¶
AlertOnFailure sets the config setting for a locker
func AlertOnOverwrite ¶
AlertOnOverwrite sets the config setting for a locker
func DefaultQueue ¶
DefaultQueue sets the config setting for a locker
func LeaseDuration ¶
LeaseDuration sets the config setting for a locker
func LeaseTimeout ¶
LeaseTimeout sets the config setting for a locker
func MaxRetries ¶
MaxRetries sets the config setting for a locker
func QueueFromContext ¶
QueueFromContext retrieves the per-request queue from context
Types ¶
type EntityFactory ¶
type EntityFactory func() Lockable
EntityFactory creates a new entity instance for use by the lock handler
type Error ¶
type Error struct { Response int // contains filtered or unexported fields }
Error is a custom error that includes the recommended http response to return to control task completion / re-attempts.
type Lock ¶
type Lock struct { // Timestamp is the time that this lock was written Timestamp time.Time `datastore:"lock_ts"` // Request is the request id that obtained the current lock RequestID string `datastore:"lock_req,noindex"` // Sequence is the task sequence number Sequence int `datastore:"lock_seq,noindex"` // Retries is the number of retries that have been attempted Retries int `datastore:"lock_try,noindex"` }
Lock adds additional information to a datastore entity used to ensure that only a single instance of a task can execute and a sequence of tasks will execute in the correct order.
The appengine taskqueue guaranteed at-least-once task execution so we need to try to detect and prevent spurious re-execution. At the same time, these repeat executions may be necessary if a task has died or disconnected and left things in an unknown state - the lock information can be used to avoid deadlocks by allowing a lease to timeout in a controlled manner.
This lock struct should be embedded within the entity:
MyEntity struct { locker.Lock Value string `datastore:"value"` }
type Lockable ¶
type Lockable interface { // Complete marks the current lock as complete Complete() // contains filtered or unexported methods }
Lockable is the interface that lockable entities must implement they will do this automatically simply by embedding lock in the struct This is used to ensure than entities we deal with have our Lock struct embedded and gives us a way to access it
type Locker ¶
type Locker struct { // Once a lock has been held longer than this duration the logs API // will be checked to determine if the request has completed or not LeaseDuration time.Duration // On rare occassions entries may be missing from the logs so if a // lock has been held for more than this duration we assume that the // task has died. 10 mins is the task timeout on a frontend instance. LeaseTimeout time.Duration // MaxRetries is the maximum number of retries to allow MaxRetries int // LogVerbose sets verbose logging of lock operations LogVerbose bool // AlertOnFailure will set an alert email to be sent to admins if // a task fails permanently (more than the MaxRetries reached) AlertOnFailure bool // AlertOnOverwrite will set an alert email to be sent to admins // if a lock is being overwritten. This is normally an exceptional // situation but may investigation to ensure correct operation of // the system AlertOnOverwrite bool // DefaultQueue is the name of the task-queue to schedule tasks on. // The default (empty string) is to use the default task queue. DefaultQueue string // Host is the name of the host to schedule tasks to run on. // This is better controlled using the target property of the taskqueue // but when running in the dev environment that doesn't work so this // provides a way to override it Host string }
Locker is the instance that stores configuration
func (*Locker) Aquire ¶
Aquire attempts to get and lock an entity with the given identifier If successful it will write a new lock entity to the datastore and return nil, otherwise it will return an error to indicate the reason for failure.
func (*Locker) Handle ¶
func (l *Locker) Handle(handler TaskHandler, factory EntityFactory) http.Handler
Handle wraps a task handler with task / lock processing
func (*Locker) NewTask ¶
func (l *Locker) NewTask(key *datastore.Key, entity Lockable, path string, params url.Values) *taskqueue.Task
NewTask creates a new taskqueue.Task for the entity with the correct headers set to match those on the entity