Project

goalkeeper

0.0
No commit activity in last 3 years
No release in over 3 years
Goalkeeper is a system for verifing if specific goals have been met by an application.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 1.7
~> 5.0
~> 10.0

Runtime

< 5.0, >= 3
 Project Readme

Goalkeeper

Goalkeeper is a simple library for tracking if, and when, a Goal has been met. A Set of goals can be combined to check if all of them have been completed.

This could be used as a checklist for process completion.

Examples

Check if your application ran its daily backup

# send the report and mark the report as sent
def backup
  # ... backup code ...
  Goalkeeper.met!("backup:#{Date.today}")
end

# elsewhere warn if any customer has not had a report sent
def did_backup_today?
  Goalkeeper.met?("backup:#{Date.today}")
end

Wait for a Set of Goals to be met before starting another.

# The email can't be sent until the 'prices' and 'awards' are downloaded
def email_report
  set = Goalkeeper::Set.new.
    add("prices:#{Date.today}").
    add("awards:#{Date.today}")

  if set.met?
    log.info "Downloads completed by #{set.met_at}"
    deliver
  else
    log.info "#{set.unmet.map(&:label).join(', ')} have not been downloaded"
    retry_later
  end
end

# elsewhere the code to get the data and mark it complete
def download_prices
  # ... download code ...
  Goalkeeper.met!('prices:#{Date.today}')
end

def download_awards
  # ... download code ...
  Goalkeeper.met!('awards:#{Date.today}')
end

Installation

Add this line to your application's Gemfile:

gem 'goalkeeper'

And then execute:

$ bundle

Or install it yourself as:

$ gem install goalkeeper

Usage

Its goes likes this...

You might never need to reference the Goal class. Most everything can be done via Goalkeeper and Goalkeeper::Set.

Goalkeeper.met? "label" #=> false
Goalkeeper.met! "label" #=> <Goalkeeper::Goal>
Goalkeeper.met? "label" #=> true

But lets have a granular example. Lets ensure we wakeup New Years Day 2020. The Goal will be named 'wakeup:2020-01-01'

g = Goalkeeper::Goal.new('wakeup:2020-01-01')
g.met? #=> false

Time flies... it is New Years Day 2020.

g.met! # or Goalkeeper.met!('wakeup:2020-01-01')
g.met? #=> true
g.met_at #=> 2020-01-01 05:01:31 -0500

Now if our application checks our goal, it will be met.

Goalkeeper.met?('wakeup:2020-01-01') #=> true
# or
Goalkeeper::Goal.new('wakeup:2020-01-01').met? #=> true

Note: Once a Goal is 'met' the 'met_at' timestamp will not change, unless 'clear!' is called.

We are probably only interested in this goal being complete for a limited time, so it will expire and be removed from Redis.

g.ttl #=> 86400 (1 day)

If you need to reference the Redis key

g.key #=> Goalkeeper:wakeup:2020-01-01

Finally deleting the Goal is simple

g.clear!
g.met? #=> false

Sets

Perhaps you have a series of Goals you want to track, and see if they all have been met, or not.

set = Goalkeeper::Set.new
set.add('goal1').add('goal2')
set.met? #=> false

Lets have 1 goal met:

Goalkeeper.met!('goal1')

But our set is not met yet

set.met? #=> false

See which goals are met, or unmet

set.met #=> [#<Goalkeeper::Goal @label="goal1">]
set.unmet #=> [#<Goalkeeper::Goal @label="goal2">]

Lets complete our set.

Goalkeeper.met!('goal1')
set.met? #=> true

See the time the final goal was met

set.met_at #=> 2015-01-01 08:02:15 -0500

Customization

Customize the redis client by setting it in your application

Goalkeeper.redis = your_redis_client

Each record has a default expiration of 24 hours, but this can be modified.

Goalkeeper.expiration = number_of_seconds

Redis keys are stored under the default namespace of "Goalkeeper:". The namespace can be configured:

Goalkeeper.namespace = string

API

Goal

method description example
new(label) Creates a new Goal with the unique label g = Goal.new('process')
met? Returns true if the Goal has been met g.met? #=> false
met! Marks the goal as completed with a timestamp g.met! #=> Time.now
met_at Nil if unmet, otherwise returns the time the Goal was met. g.met_at #=> 2015-02-09 22:24:07 -0500
ttl The Redis ttl value if there is a record for the goal. g.ttl #=> 86400
key The key used to store the record in Redis. g.key #=> "Goalkeeper:process"
clear! Deletes the met record. Goal is now unmet. g.clear!

Set

method description example
new creates an empty set of goals. s = set.new
add(label) Adds a new Goal the Set. chainable s.add('process.a').add('process.b')
met? Returns true if all the Set's Goals have been met. s.met? #=> false
met_at Returns the most recent met_at for the Set's Goals. Nil if no Goal met. s.met_at #=> 2015-02-09 22:24:07 -0500
met Returns a new Set with all Goals which have been met. s.met #=> Set(...)
unmet Returns a new Set with all Goals which have not been met. s.unmet #=> Set(...)

Goalkeeper

method description example
::met!(label) Creates a new Goal and marks it met. Goalkeeper.met!('process') #=> <Goalkeepr::Goal>
::met?(label) Checks if the label has been met or not Goalkeeper.met?('process') #=> true

Contributing

  1. Fork it ( https://github.com/jweir/goalkeeper/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request