thinner 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,121 @@
1
+ pre.dawn .MetaSeparator {
2
+ font-weight: bold;
3
+ background-color: #DCDCDC;
4
+ color: #19356D;
5
+ }
6
+ pre.dawn .SupportVariable {
7
+ color: #234A97;
8
+ }
9
+ pre.dawn .Constant {
10
+ font-weight: bold;
11
+ color: #811F24;
12
+ }
13
+ pre.dawn .EmbeddedSource {
14
+ background-color: #829AC2;
15
+ }
16
+ pre.dawn .StringRegexpConstantCharacterEscape {
17
+ font-weight: bold;
18
+ color: #811F24;
19
+ }
20
+ pre.dawn .Support {
21
+ color: #691C97;
22
+ }
23
+ pre.dawn .MarkupList {
24
+ color: #693A17;
25
+ }
26
+ pre.dawn .Storage {
27
+ color: #A71D5D;
28
+ font-style: italic;
29
+ }
30
+ pre.dawn .line-numbers {
31
+ background-color: #7496CF;
32
+ color: #000000;
33
+ }
34
+ pre.dawn .StringConstant {
35
+ font-weight: bold;
36
+ color: #696969;
37
+ }
38
+ pre.dawn .MarkupUnderline {
39
+ text-decoration: underline;
40
+ color: #080808;
41
+ }
42
+ pre.dawn .MarkupHeading {
43
+ font-weight: bold;
44
+ color: #19356D;
45
+ }
46
+ pre.dawn .SupportConstant {
47
+ color: #B4371F;
48
+ }
49
+ pre.dawn .MarkupQuote {
50
+ background-color: #C5C5C5;
51
+ color: #0B6125;
52
+ font-style: italic;
53
+ }
54
+ pre.dawn .StringRegexpSpecial {
55
+ font-weight: bold;
56
+ color: #CF5628;
57
+ }
58
+ pre.dawn .InvalidIllegal {
59
+ background-color: #B52A1D;
60
+ color: #F8F8F8;
61
+ font-style: italic;
62
+ }
63
+ pre.dawn .MarkupDeleted {
64
+ color: #B52A1D;
65
+ }
66
+ pre.dawn .MarkupRaw {
67
+ background-color: #C5C5C5;
68
+ color: #234A97;
69
+ }
70
+ pre.dawn .SupportFunction {
71
+ color: #693A17;
72
+ }
73
+ pre.dawn .PunctuationSeparator {
74
+ color: #794938;
75
+ }
76
+ pre.dawn .StringRegexp {
77
+ color: #CF5628;
78
+ }
79
+ pre.dawn .StringEmbeddedSource {
80
+ background-color: #829AC2;
81
+ color: #080808;
82
+ }
83
+ pre.dawn .MarkupLink {
84
+ color: #234A97;
85
+ font-style: italic;
86
+ }
87
+ pre.dawn .MarkupBold {
88
+ font-weight: bold;
89
+ color: #080808;
90
+ }
91
+ pre.dawn .StringVariable {
92
+ color: #234A97;
93
+ }
94
+ pre.dawn .String {
95
+ color: #0B6125;
96
+ }
97
+ pre.dawn .Keyword {
98
+ color: #794938;
99
+ }
100
+ pre.dawn {
101
+ background-color: #F5F5F5;
102
+ color: #080808;
103
+ }
104
+ pre.dawn .MarkupItalic {
105
+ color: #080808;
106
+ font-style: italic;
107
+ }
108
+ pre.dawn .InvalidDeprecated {
109
+ font-weight: bold;
110
+ color: #B52A1D;
111
+ }
112
+ pre.dawn .Variable {
113
+ color: #234A97;
114
+ }
115
+ pre.dawn .Entity {
116
+ color: #BF4F24;
117
+ }
118
+ pre.dawn .Comment {
119
+ color: #5A525F;
120
+ font-style: italic;
121
+ }
@@ -0,0 +1,53 @@
1
+ body {
2
+ font-family: Garamond, Baskerville, "Baskerville Old Face", "Hoefler Text", "Times New Roman", serif;
3
+ font-size: 16px;
4
+ line-height:20px;
5
+ width: 600px;
6
+ margin-left:auto;
7
+ margin-right:auto;
8
+ background: #f4f4f4;
9
+ }
10
+ a.propublica{
11
+ position:absolute;
12
+ background: transparent url(../images/proplogo.png) no-repeat -40px -20px;
13
+ top: 0;
14
+ left: 0;
15
+ width: 160px;
16
+ height: 141px;
17
+ }
18
+
19
+ pre {
20
+ font-family: Monaco, Courier, monospace;
21
+ font-size: 12px;
22
+ line-height: 16px;
23
+ padding:0.5em 1em;
24
+ overflow: auto;
25
+ border-left: 4px solid #143D8D;
26
+ margin-left: 1em;
27
+ }
28
+ a {
29
+ color: #143D8D;
30
+ text-decoration: none;
31
+ font-weight: bold;
32
+ }
33
+ ul {
34
+ margin:0 1em;
35
+ padding:0;
36
+ list-style: none;
37
+ }
38
+ li {
39
+ margin:0;
40
+ padding:0;
41
+ }
42
+ strong {
43
+ font-family: Monaco, Courier, monospace;
44
+ font-weight: normal;
45
+ background: #dadee5;
46
+ border: 1px solid #aaa;
47
+ padding: 1px 2px;
48
+ font-size: 12px;
49
+ }
50
+ p{ margin: 0 0 1em 0 }
51
+ h3{
52
+ margin-bottom: 0px;
53
+ }
@@ -0,0 +1,25 @@
1
+ Thinner.configure do |config|
2
+ # Number of urls to purge at one time. These purge requests are fired in quick
3
+ # succession. Thinner is perfectly capable of killing a Varnish server, by
4
+ # overloading the worker thread, so be really conservative with this option.
5
+ config.batch_length = 10
6
+
7
+ # The amount of time to sleep between purges in seconds.
8
+ config.sleep_time = 1
9
+
10
+ # The server address and management port. See:
11
+ # http://www.varnish-cache.org/trac/wiki/ManagementPort
12
+ # for details.
13
+ config.server = "127.0.0.1:6082"
14
+
15
+ # By default, every time you call Thinner.purge! thinner spins off a new
16
+ # instance of Thinner::Client and terminates any old instances that are
17
+ # running. If you want to have overlapping instances set this to true.
18
+ # It's not recommended to have multiple Thinner::Client's running at the
19
+ # same time.
20
+ config.no_kill = false
21
+
22
+ # The log file (either a string or file object) to log the current batch to.
23
+ # Defaults to STDOUT
24
+ config.log_file = STDOUT
25
+ end
@@ -0,0 +1,5 @@
1
+ # The urls in this array are purged in order, so you'll want to structure it
2
+ # according to usage.
3
+ arr << ["/some_route", "/"]
4
+
5
+ Thinner.purge! arr
Binary file
@@ -0,0 +1,64 @@
1
+ <%
2
+ $:.unshift File.expand_path(File.dirname(__FILE__), "/../lib/thinner")
3
+ DOCS = "documentation/examples/"
4
+ require 'uv'
5
+ def code_for(file)
6
+ return '' unless File.exists?("#{DOCS}#{file}.rb")
7
+ file = File.open("#{DOCS}#{file}.rb").read
8
+ Uv.parse(file, "xhtml", "ruby", false, "dawn", false)
9
+ end
10
+ %>
11
+ <!DOCTYPE html>
12
+ <html>
13
+ <head>
14
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
15
+ <title>Thinner -- Version <%= File.read('VERSION') %></title>
16
+ <link rel="stylesheet" type="text/css" href="documentation/css/styles.css" />
17
+ <link rel="stylesheet" type="text/css" href="documentation/css/dawn.css" />
18
+ </head>
19
+ <body>
20
+ <a href="http://www.propublica.org" class="propublica">&nbsp;</a>
21
+ <h1>Thinner &ndash; Version <%= File.read('VERSION') %></h1>
22
+ <p><a href="https://github.com/propublica/Thinner">Thinner</a> is a utility
23
+ for purging urls from a Varnish server.</p>
24
+ <p>When you are deploying code changes to a server under load, the uncached
25
+ load can quickly bring down your backend server even with Varnish's grace
26
+ mode. Often, allowing stale caches to stick around for a while saves
27
+ both server performance and sanity.</p>
28
+ <p>Thinner gives you fine-grained control over wildcard purging, and rolls
29
+ purges out slowly. Your users will see stale pages from the previous deploy
30
+ until Thinner has finished invalidating the stale cache at a rate that you set.
31
+ If you have a bunch of pages you need to invalidate en masse, but don't
32
+ want to risk overloading your server, Thinner is for you.</p>
33
+ <p>All that being said, Thinner isn't really a solution for observing
34
+ model changes and purging associated urls. If you have a highly dynamic
35
+ application, it's worlds better to handle purging via a
36
+ <a href="http://github.com/russ/lacquer/blob/master/lib/lacquer/delayed_job_job.rb">job server</a>
37
+ outside of the request-response flow.</p>
38
+ <p><a href="doc/index.html">API docs</a> | <a href="http://github.com/propublica/thinner/issues">Issue Tracker</a></p>
39
+ <h2>Installation</h2>
40
+ <p>Thinner is available via rubygems:
41
+ <pre>gem install thinner</pre>
42
+ <h2>Usage</h2>
43
+ <p>Thinner has both a library and command-line interface. To use it as a gem
44
+ you'll first have to configure how it works by calling <strong>Thinner.configure</strong>.
45
+ Here's a quick rundown of all of the options available:</p>
46
+ <%= code_for "configure" %>
47
+ <p>Once you have the configuration in place call <strong>purge!</strong> with
48
+ an array of urls:</p>
49
+ <%= code_for "purge" %>
50
+ <p>Thinner will then fork a background process and purge the urls. You can
51
+ check the progress of the purge by tailing the log file or with:</p>
52
+ <pre>varnishlog | grep purge</pre>
53
+ <p>If ruby's not your cup of tea, Thinner also has a command line interface.
54
+ Once you've installed the gem run <strong>thinner -h</strong> to see the
55
+ available options.</p>
56
+ <p>The command line interface accepts a newline separated list of urls via
57
+ stdin by setting the <strong>-e</strong> flag. So you'll be able to use
58
+ the command like so:</p>
59
+ <pre>cat urls_to_purge.txt | bin/thinner -e</pre>
60
+ <h2>Change Log</h2>
61
+ <h3>0.1.0</h3>
62
+ <p>Initial release.</p>
63
+ </body>
64
+ </html>
data/index.html ADDED
@@ -0,0 +1,87 @@
1
+
2
+ <!DOCTYPE html>
3
+ <html>
4
+ <head>
5
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
6
+ <title>Thinner -- Version 0.1.0
7
+ </title>
8
+ <link rel="stylesheet" type="text/css" href="documentation/css/styles.css" />
9
+ <link rel="stylesheet" type="text/css" href="documentation/css/dawn.css" />
10
+ </head>
11
+ <body>
12
+ <a href="http://www.propublica.org" class="propublica">&nbsp;</a>
13
+ <h1>Thinner &ndash; Version 0.1.0
14
+ </h1>
15
+ <p><a href="https://github.com/propublica/Thinner">Thinner</a> is a utility
16
+ for purging urls from a Varnish server.</p>
17
+ <p>When you are deploying code changes to a server under load, the uncached
18
+ load can quickly bring down your backend server even with Varnish's grace
19
+ mode. Often, allowing stale caches to stick around for a while saves
20
+ both server performance and sanity.</p>
21
+ <p>Thinner gives you fine-grained control over wildcard purging, and rolls
22
+ purges out slowly. Your users will see stale pages from the previous deploy
23
+ until Thinner has finished invalidating the stale cache at a rate that you set.
24
+ If you have a bunch of pages you need to invalidate en masse, but don't
25
+ want to risk overloading your server, Thinner is for you.</p>
26
+ <p>All that being said, Thinner isn't really a solution for observing
27
+ model changes and purging associated urls. If you have a highly dynamic
28
+ application, it's worlds better to handle purging via a
29
+ <a href="http://github.com/russ/lacquer/blob/master/lib/lacquer/delayed_job_job.rb">job server</a>
30
+ outside of the request-response flow.</p>
31
+ <p><a href="doc/index.html">API docs</a> | <a href="http://github.com/propublica/thinner/issues">Issue Tracker</a></p>
32
+ <h2>Installation</h2>
33
+ <p>Thinner is available via rubygems:
34
+ <pre>gem install thinner</pre>
35
+ <h2>Usage</h2>
36
+ <p>Thinner has both a library and command-line interface. To use it as a gem
37
+ you'll first have to configure how it works by calling <strong>Thinner.configure</strong>.
38
+ Here's a quick rundown of all of the options available:</p>
39
+ <pre class="dawn"><span class="Support">Thinner</span><span class="PunctuationSeparator">.</span><span class="Entity">configure</span> <span class="Keyword">do </span><span class="PunctuationSeparator">|</span><span class="Variable">config</span><span class="PunctuationSeparator">|</span>
40
+ <span class="Comment"> <span class="Comment">#</span> Number of urls to purge at one time. These purge requests are fired in quick</span>
41
+ <span class="Comment"> <span class="Comment">#</span> succession. Thinner is perfectly capable of killing a Varnish server, by</span>
42
+ <span class="Comment"> <span class="Comment">#</span> overloading the worker thread, so be really conservative with this option.</span>
43
+ config<span class="PunctuationSeparator">.</span><span class="Entity">batch_length</span> <span class="Keyword">=</span> <span class="Constant">10</span>
44
+
45
+ <span class="Comment"> <span class="Comment">#</span> The amount of time to sleep between purges in seconds.</span>
46
+ config<span class="PunctuationSeparator">.</span><span class="Entity">sleep_time</span> <span class="Keyword">=</span> <span class="Constant">1</span>
47
+
48
+ <span class="Comment"> <span class="Comment">#</span> The server address and management port. See:</span>
49
+ <span class="Comment"> <span class="Comment">#</span> http://www.varnish-cache.org/trac/wiki/ManagementPort</span>
50
+ <span class="Comment"> <span class="Comment">#</span> for details.</span>
51
+ config<span class="PunctuationSeparator">.</span><span class="Entity">server</span> <span class="Keyword">=</span> &quot;127.0.0.1:6082&quot;
52
+
53
+ <span class="Comment"> <span class="Comment">#</span> By default, every time you call Thinner.purge! thinner spins off a new</span>
54
+ <span class="Comment"> <span class="Comment">#</span> instance of Thinner::Client and terminates any old instances that are</span>
55
+ <span class="Comment"> <span class="Comment">#</span> running. If you want to have overlapping instances set this to true.</span>
56
+ <span class="Comment"> <span class="Comment">#</span> It's not recommended to have multiple Thinner::Client's running at the</span>
57
+ <span class="Comment"> <span class="Comment">#</span> same time.</span>
58
+ config<span class="PunctuationSeparator">.</span><span class="Entity">no_kill</span> <span class="Keyword">=</span> <span class="Constant">false</span>
59
+
60
+ <span class="Comment"> <span class="Comment">#</span> The log file (either a string or file object) to log the current batch to.</span>
61
+ <span class="Comment"> <span class="Comment">#</span> Defaults to STDOUT</span>
62
+ config<span class="PunctuationSeparator">.</span><span class="Entity">log_file</span> <span class="Keyword">=</span> <span class="Variable">STDOUT</span>
63
+ <span class="Keyword">end</span>
64
+ </pre>
65
+ <p>Once you have the configuration in place call <strong>purge!</strong> with
66
+ an array of urls:</p>
67
+ <pre class="dawn"><span class="Comment"><span class="Comment">#</span> The urls in this array are purged in order, so you'll want to structure it</span>
68
+ <span class="Comment"><span class="Comment">#</span> according to usage.</span>
69
+ arr <span class="Keyword">&lt;&lt;</span> [&quot;/some_route&quot;<span class="PunctuationSeparator">,</span> &quot;/&quot;]
70
+
71
+ <span class="Support">Thinner</span><span class="PunctuationSeparator">.</span><span class="Entity">purge!</span> arr
72
+ </pre>
73
+ <p>Thinner will then fork a background process and purge the urls. You can
74
+ check the progress of the purge by tailing the log file or with:</p>
75
+ <pre>varnishlog | grep purge</pre>
76
+ <p>If ruby's not your cup of tea, Thinner also has a command line interface.
77
+ Once you've installed the gem run <strong>thinner -h</strong> to see the
78
+ available options.</p>
79
+ <p>The command line interface accepts a newline separated list of urls via
80
+ stdin by setting the <strong>-e</strong> flag. So you'll be able to use
81
+ the command like so:</p>
82
+ <pre>cat urls_to_purge.txt | bin/thinner -e</pre>
83
+ <h2>Change Log</h2>
84
+ <h3>0.1.0</h3>
85
+ <p>Initial release.</p>
86
+ </body>
87
+ </html>
@@ -0,0 +1,88 @@
1
+ require 'logger'
2
+
3
+ module Thinner
4
+
5
+ # A Thinner::Client runs as a background process and purges a list of urls
6
+ # in batches.
7
+ class Client
8
+
9
+ # A list of successfully purged urls.
10
+ attr_reader :purged_urls
11
+
12
+ # The list of Errors we want to catch.
13
+ ERRORS = [Varnish::Error, Varnish::BrokenConnection, Varnish::CommandFailed, Timeout::Error, Errno::ECONNREFUSED]
14
+
15
+ # Before purging, each Thinner::Client grabs various configuration settings
16
+ # and makes a copy of the passed in urls.
17
+ def initialize(urls)
18
+ @batch = Thinner.configuration.batch_length
19
+ @timeout = Thinner.configuration.sleep_time
20
+ @varnish = Varnish::Client.new Thinner.configuration.server
21
+ @log_file = Thinner.configuration.log_file
22
+ @purged_urls = []
23
+ @urls = Array.new urls
24
+ @length = @urls.length
25
+ logger
26
+ handle_errors
27
+ end
28
+
29
+ # Kickstart the purging process and loop through the array until there aren't
30
+ # any urls left to purge. Each time the loop runs it will update the process
31
+ # label with the first url in the list.
32
+ def run!
33
+ while @urls.length > 0
34
+ @current_job = @urls.slice! 0, @batch
35
+ $0 = "#{PROCESS_IDENTIFIER}: purging #{@current_job.first}"
36
+ purge_urls
37
+ sleep @timeout
38
+ end
39
+ close_log
40
+ end
41
+
42
+ private
43
+
44
+ # Once a batch is ready the Client fires off purge requests on the list of
45
+ # urls.
46
+ def purge_urls
47
+ @current_job.each do |url|
48
+ begin
49
+ @varnish.start if @varnish.stopped?
50
+ while(!@varnish.running?) do sleep 0.1 end
51
+ if @varnish.purge :url, url
52
+ @logger.info "Purged url: #{url}"
53
+ @purged_urls << url
54
+ else
55
+ @logger.warn "Could not purge: #{url}"
56
+ end
57
+ rescue *ERRORS => e
58
+ @logger.warn "Error on url: #{url}, message: #{e}"
59
+ sleep @timeout
60
+ end
61
+ end
62
+ end
63
+
64
+ # Trap certain signals so the Client can report back the progress of the
65
+ # job and close the log.
66
+ def handle_errors
67
+ trap('TERM') { close_log }
68
+ trap('KILL') { close_log }
69
+ trap('INT') { close_log }
70
+ end
71
+
72
+ # The logger redirects all STDOUT writes to a logger instance.
73
+ def logger
74
+ if !@log_file.respond_to?(:write)
75
+ STDOUT.reopen(File.open(@log_file, (File::WRONLY | File::APPEND | File::CREAT)))
76
+ end
77
+ @logger = Logger.new(STDOUT)
78
+ end
79
+
80
+ # Log the purged urls and exit the process.
81
+ def close_log
82
+ @logger.info "Purged #{@purged_urls.length} of #{@length} urls."
83
+ @logger.info "Exiting..."
84
+ end
85
+
86
+ end
87
+
88
+ end
@@ -0,0 +1,80 @@
1
+ require 'optparse'
2
+ require File.expand_path("#{File.dirname __FILE__}/../thinner.rb")
3
+
4
+ module Thinner
5
+
6
+ class CommandLine
7
+
8
+ # Usage and summary
9
+ BANNER = <<-EOF
10
+ Thinner purges varnish caches as slowly as you need it to.
11
+
12
+ Documentation: http://propublica.github.com/thinner/
13
+
14
+ Usage: thinner OPTIONS URL
15
+
16
+ Options:
17
+ EOF
18
+ # Create a Thinner::CommandLine, parse any associated options, grab a list
19
+ # of urls and start the process
20
+ def initialize
21
+ @urls = []
22
+ options!
23
+ @urls ||= ARGV
24
+ run!
25
+ end
26
+
27
+ # Build a Thinner::Configuration instance from the passed in options and go
28
+ # to the races.
29
+ def run!
30
+ Thinner.configure do |config|
31
+ @options.each_pair do |key, value|
32
+ config.send("#{key}=".to_sym, value)
33
+ end
34
+ end
35
+ Thinner.purge! @urls
36
+ end
37
+
38
+ private
39
+
40
+ # Parse the command line options using OptionParser.
41
+ def options!
42
+ @options = {}
43
+ @option_parser = OptionParser.new(BANNER) do |opts|
44
+ opts.on("-b", "--batch_length BATCH", "Number of urls to purge at once") do |b|
45
+ @options[:batch_length] = b.to_i
46
+ end
47
+ opts.on("-t", "--sleep_time SLEEP", "Time to wait in between batches") do |t|
48
+ @options[:sleep_time] = t.to_i
49
+ end
50
+ opts.on("-e", "--stdin", "Use stdin for urls") do
51
+ ARGF.each_line do |url|
52
+ @urls << url.chomp
53
+ end
54
+ end
55
+ opts.on("-s", "--server SERVER", "Varnish url, e.g. 127.0.0.1:6082") do |s|
56
+ @options[:server] = s
57
+ end
58
+ opts.on("-o", "--log_file LOG_PATH", "Log file to output to (default: Standard Out") do |o|
59
+ @options[:log_file] = o
60
+ end
61
+ opts.on("-n", "--no-kill", "Don't kill the running purgers if they exist") do |n|
62
+ @options[:no_kill] = n
63
+ end
64
+ opts.on_tail("-h", "--help", "Display this help message") do
65
+ puts opts.help
66
+ exit
67
+ end
68
+ end
69
+
70
+ begin
71
+ @option_parser.parse!(ARGV)
72
+ rescue OptionParser::InvalidOption => e
73
+ puts e.message
74
+ exit(1)
75
+ end
76
+ end
77
+
78
+ end
79
+
80
+ end
@@ -0,0 +1,37 @@
1
+ module Thinner
2
+
3
+ # Thinner::Configuration holds the various settings for Thinner
4
+ class Configuration
5
+
6
+ attr_accessor :batch_length, :sleep_time, :server, :log_file, :no_kill
7
+
8
+ # Create a Thinner::Configuration instance with sane defaults.
9
+ def initialize
10
+ # Number of urls to purge at one time. These purge requests are fired in quick
11
+ # succession. Thinner is perfectly capable of killing a Varnish server, by
12
+ # overloading the worker thread, so be really conservative with this option.
13
+ @batch_length = 10
14
+
15
+ # The amount of time to sleep between purges in seconds.
16
+ @sleep_time = 1
17
+
18
+ # The server address and management port. See:
19
+ # http://www.varnish-cache.org/trac/wiki/ManagementPort
20
+ # for details.
21
+ @server = "127.0.0.1:6082"
22
+
23
+ # By default, every time you call Thinner.purge! thinner spins off a new
24
+ # instance of Thinner::Client and terminates any old instances that are
25
+ # running. If you want to have overlapping instances set this to true.
26
+ # It's not recommended to have multiple Thinner::Client's running at the
27
+ # same time.
28
+ @no_kill = false
29
+
30
+ # The log file (either a string or file object) to log the current batch to.
31
+ # Defaults to STDOUT
32
+ @log_file = STDOUT
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,46 @@
1
+ module Thinner
2
+
3
+ # A Thinner::Purger dispatches a client and ensures only one instance of a
4
+ # Thinner::Client is running at a given time.
5
+ class Purger
6
+
7
+ # Each Purger accepts a list of urls to pass on to the client to purge.
8
+ def initialize(urls)
9
+ @urls = urls
10
+ end
11
+
12
+ # After the configuration is in place and the Purger has a list of urls,
13
+ # it can fork a client process to run in the background. By default the
14
+ # Purger will kill any old Thinner::Client processes still running so as
15
+ # to not double up on purge requests.
16
+ def purge!
17
+ self.class.stop! unless Thinner.configuration.no_kill
18
+ puts "==== Starting purge see: #{Thinner.configuration.log_file} for finished urls."
19
+ client_id = fork {
20
+ Client.new(@urls).run!
21
+ }
22
+ Process.detach(client_id)
23
+ end
24
+
25
+ # A list of Thinner::Client process ids -- adapted from resque.
26
+ def self.job_ids
27
+ lines = `ps -A -o pid,command | grep #{PROCESS_IDENTIFIER}`.split("\n").map do |line|
28
+ line.split(' ')[0].to_i
29
+ end
30
+ end
31
+
32
+ # Before we spin up a new client each running process is killed by pid. Each
33
+ # killed process's id is logged in the Thinner log file.
34
+ def self.stop!
35
+ job_ids.each do |pid|
36
+ begin
37
+ Process.kill("KILL", pid.to_i)
38
+ puts "==== Killing process: #{pid}"
39
+ rescue Errno::ESRCH
40
+ end
41
+ end
42
+ end
43
+
44
+ end
45
+
46
+ end
data/lib/thinner.rb ADDED
@@ -0,0 +1,37 @@
1
+ module Thinner
2
+
3
+ # The base location of the Thinner gem.
4
+ ROOT = File.expand_path "#{File.dirname __FILE__}/.."
5
+
6
+ # The Thinner version.
7
+ VERSION = File.read("#{ROOT}/VERSION").chomp
8
+
9
+ # The process label to run each Thinner::Client under.
10
+ PROCESS_IDENTIFIER = "Thinner"
11
+
12
+ # Set up the configuration instance as a class level accessor.
13
+ class << self; attr_accessor :configuration; end
14
+
15
+ # Set any thinner settings by passing in a block.
16
+ def self.configure
17
+ self.configuration ||= Configuration.new
18
+ yield configuration
19
+ end
20
+
21
+ # Halt any running instances of Thinner::Client
22
+ def self.stop!
23
+ Purger.stop!
24
+ end
25
+
26
+ # Begin purging urls.
27
+ def self.purge! urls
28
+ Purger.new(urls).purge!
29
+ end
30
+
31
+ end
32
+
33
+ require "klarlack"
34
+ require "logger"
35
+ require "#{Thinner::ROOT}/lib/thinner/configuration"
36
+ require "#{Thinner::ROOT}/lib/thinner/client"
37
+ require "#{Thinner::ROOT}/lib/thinner/purger"
data/test/helper.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'thinner'
8
+ Thinner.configure {}
9
+ URLS = ["/"]
10
+