rack-campaign 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.textile +137 -1
- data/Rakefile +2 -2
- data/examples/campaigns.yml +16 -0
- data/examples/config.ru +6 -0
- data/examples/initscript +47 -0
- data/examples/unicorn.rb +69 -0
- metadata +7 -3
data/README.textile
CHANGED
@@ -1 +1,137 @@
|
|
1
|
-
|
1
|
+
h2. rack-campaign
|
2
|
+
|
3
|
+
This is a "Rack":http://rack.rubyforge.org/ application (a gem is available by the same name) allowing you to maintain a "YAML":http://www.yaml.org/ file of short URLs that redirect to target URLs with a set of specified Google Analytics variables. It could be used to attach any number of parameters by any name to the query string.
|
4
|
+
|
5
|
+
h2. What it does:
|
6
|
+
|
7
|
+
*example promo url*:
|
8
|
+
|
9
|
+
@http://zetetic.net/c/blog-rack-campaign@
|
10
|
+
|
11
|
+
When the user visits this link, our web server sees the /c/ location and forwards it to rack-campaign, which looks up 'blog-rack-campaign' in the YAML file, and redirects the user to the full URL, with campaign variables attached.
|
12
|
+
|
13
|
+
*resulting full url*:
|
14
|
+
|
15
|
+
@http://www.zetetic.net/blog/2010/06/11/introducing-rack-campaign?utm_campaign=rack-campaign&utm_source=blog&utm_medium=internets&utm_content=example%20link@
|
16
|
+
|
17
|
+
The former is much better than the latter, especially for newsletters and other promotional links. And with a Rack application and a YAML file you can host it yourself, you don't need to rely on bit.ly or other URL shorteners, and you can "fix" any mistakes after publishing a URL simply by updating the YAML file and reloading Unicorn (taking advantage of zero down-time!) [ _You could use another Rack-server, we like Unicorn._ ]
|
18
|
+
|
19
|
+
h2. Installation
|
20
|
+
|
21
|
+
@gem install rack-campaign@
|
22
|
+
|
23
|
+
The rest depends on how you intend to use it.
|
24
|
+
|
25
|
+
h2. Example Files
|
26
|
+
|
27
|
+
In the @/examples@ directory of the source distribution are some sample configuration files. @config.ru@ is a @rackup@ file, initializing the rack-campaign middleware. You don't have to use rack-campaign as a stand-alone Rack application, you could instead use it in a middleware stack (although you might want to modify it's behavior). You probably want to use the map directive in that case to assign rack-campaign to a particular url path (we use /c).
|
28
|
+
|
29
|
+
h2. Example Configuration
|
30
|
+
|
31
|
+
This is how we use rack-campaign as a stand-alone Rack application. Nginx is our web-server, and we use Unicorn to serve up rack-campaign for the /c path:
|
32
|
+
|
33
|
+
*/www/campaigns/campaigns.yml*:
|
34
|
+
|
35
|
+
<pre><code>
|
36
|
+
blog-rack-campaign:
|
37
|
+
url: http://dev.zetetic.net/blog/2010/06/11/introducing-rack-campaign
|
38
|
+
tokens:
|
39
|
+
campaign: rack-campaign
|
40
|
+
source: blog
|
41
|
+
medium: internets
|
42
|
+
content: example link
|
43
|
+
|
44
|
+
blog-getstrip:
|
45
|
+
url: http://getstrip.com
|
46
|
+
tokens:
|
47
|
+
campaign: rack-campaign
|
48
|
+
source: blog
|
49
|
+
medium: internets
|
50
|
+
term: strip rocks!
|
51
|
+
content: example link
|
52
|
+
</code></pre>
|
53
|
+
|
54
|
+
*/www/campaigns/config.ru*:
|
55
|
+
|
56
|
+
<pre><code>
|
57
|
+
# Rack-up application config
|
58
|
+
|
59
|
+
require 'rubygems'
|
60
|
+
require 'rack/zetetic/rack-campaign'
|
61
|
+
|
62
|
+
run Rack::Zetetic::CampaignLink.new('/www/campaigns/campaigns.yml')
|
63
|
+
</code></pre>
|
64
|
+
|
65
|
+
*nginx.conf*:
|
66
|
+
|
67
|
+
<pre><code>
|
68
|
+
# define upstream for campaign routing
|
69
|
+
upstream campaigns {
|
70
|
+
server unix:/www/campaigns/tmp/sockets/unicorn.sock;
|
71
|
+
}
|
72
|
+
|
73
|
+
location /c {
|
74
|
+
proxy_redirect off;
|
75
|
+
proxy_set_header Host $host;
|
76
|
+
proxy_set_header X-Real-IP $remote_addr;
|
77
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
78
|
+
proxy_max_temp_file_size 0;
|
79
|
+
|
80
|
+
# forward everything else to the mongrel cluster
|
81
|
+
if (!-f $request_filename) {
|
82
|
+
proxy_pass http://campaigns;
|
83
|
+
break;
|
84
|
+
}
|
85
|
+
}
|
86
|
+
</code></pre>
|
87
|
+
|
88
|
+
*/etc/init.d/unicorn_rack*:
|
89
|
+
|
90
|
+
<pre><code>
|
91
|
+
#!/bin/bash
|
92
|
+
#
|
93
|
+
# unicorn_rack Startup script for Unicorn master processes
|
94
|
+
#
|
95
|
+
# chkconfig: - 85 15
|
96
|
+
# description: unicorn is a magical process offering up workers to nginx
|
97
|
+
#
|
98
|
+
|
99
|
+
USER=mongrel
|
100
|
+
RETVAL=0
|
101
|
+
APPS=( '/www/campaigns' )
|
102
|
+
|
103
|
+
for APP in "${APPS[@]}"
|
104
|
+
do
|
105
|
+
case "$1" in
|
106
|
+
start)
|
107
|
+
echo "Starting up $APP"
|
108
|
+
cd $APP
|
109
|
+
sudo -u $USER unicorn -c $APP/unicorn.rb -E production -D
|
110
|
+
RETVAL=$?
|
111
|
+
;;
|
112
|
+
stop)
|
113
|
+
echo "Stopping $APP"
|
114
|
+
PID=`ps auxw | grep 'unicorn master' | grep $APP | grep -v grep | awk '{ print $2 }'`
|
115
|
+
sudo -u $USER kill -INT $PID
|
116
|
+
RETVAL=$?
|
117
|
+
;;
|
118
|
+
restart)
|
119
|
+
$0 stop
|
120
|
+
sleep 2
|
121
|
+
$0 start
|
122
|
+
;;
|
123
|
+
reload)
|
124
|
+
echo "Re-loading $APPS"
|
125
|
+
PID=`ps auxw | grep 'unicorn master' | grep $APP | grep -v grep | awk '{ print $2 }'`
|
126
|
+
sudo -u $USER kill -HUP $PID
|
127
|
+
RETVAL=$?
|
128
|
+
;;
|
129
|
+
*)
|
130
|
+
echo "Usage: unicorn_rack {start|stop|restart|reload}"
|
131
|
+
exit 1
|
132
|
+
;;
|
133
|
+
esac
|
134
|
+
done
|
135
|
+
|
136
|
+
exit $RETVAL
|
137
|
+
</code></pre>
|
data/Rakefile
CHANGED
@@ -5,7 +5,7 @@ require 'date'
|
|
5
5
|
require 'spec/rake/spectask'
|
6
6
|
|
7
7
|
GEM = "rack-campaign"
|
8
|
-
GEM_VERSION = "0.0.
|
8
|
+
GEM_VERSION = "0.0.3"
|
9
9
|
AUTHOR = "Billy Gray"
|
10
10
|
EMAIL = "wgray@zetetic.net"
|
11
11
|
HOMEPAGE = "http://github.com/billymeltdown/rack-campaign"
|
@@ -25,7 +25,7 @@ spec = Gem::Specification.new do |s|
|
|
25
25
|
s.homepage = HOMEPAGE
|
26
26
|
s.add_dependency "rack"
|
27
27
|
s.require_path = 'lib'
|
28
|
-
s.files = %w(LICENSE README.textile Rakefile) + Dir.glob("{lib}/**/*")
|
28
|
+
s.files = %w(LICENSE README.textile Rakefile) + Dir.glob("{lib}/**/*") + Dir.glob("examples/**/*")
|
29
29
|
end
|
30
30
|
|
31
31
|
task :default => :spec
|
@@ -0,0 +1,16 @@
|
|
1
|
+
blog-rack-campaign:
|
2
|
+
url: http://dev.zetetic.net/blog/2010/06/11/introducing-rack-campaign
|
3
|
+
tokens:
|
4
|
+
campaign: rack-campaign
|
5
|
+
source: blog
|
6
|
+
medium: internets
|
7
|
+
content: example link
|
8
|
+
|
9
|
+
blog-getstrip:
|
10
|
+
url: http://getstrip.com
|
11
|
+
tokens:
|
12
|
+
campaign: rack-campaign
|
13
|
+
source: blog
|
14
|
+
medium: internets
|
15
|
+
term: strip rocks!
|
16
|
+
content: example link
|
data/examples/config.ru
ADDED
data/examples/initscript
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
#
|
3
|
+
# unicorn_rack Startup script for Unicorn master processes
|
4
|
+
#
|
5
|
+
# chkconfig: - 85 15
|
6
|
+
# description: unicorn is a magical process offering up workers to nginx
|
7
|
+
#
|
8
|
+
|
9
|
+
USER=mongrel
|
10
|
+
RETVAL=0
|
11
|
+
APPS=( '/www/campaigns' )
|
12
|
+
|
13
|
+
for APP in "${APPS[@]}"
|
14
|
+
do
|
15
|
+
case "$1" in
|
16
|
+
start)
|
17
|
+
echo "Starting up $APP"
|
18
|
+
cd $APP
|
19
|
+
sudo -u $USER unicorn -c $APP/unicorn.rb -E production -D
|
20
|
+
RETVAL=$?
|
21
|
+
;;
|
22
|
+
stop)
|
23
|
+
echo "Stopping $APP"
|
24
|
+
PID=`ps auxw | grep 'unicorn master' | grep $APP | grep -v grep | awk '{ print $2 }'`
|
25
|
+
sudo -u $USER kill -INT $PID
|
26
|
+
RETVAL=$?
|
27
|
+
;;
|
28
|
+
restart)
|
29
|
+
$0 stop
|
30
|
+
sleep 2
|
31
|
+
$0 start
|
32
|
+
;;
|
33
|
+
reload)
|
34
|
+
echo "Re-loading $APPS"
|
35
|
+
PID=`ps auxw | grep 'unicorn master' | grep $APP | grep -v grep | awk '{ print $2 }'`
|
36
|
+
sudo -u $USER kill -HUP $PID
|
37
|
+
RETVAL=$?
|
38
|
+
;;
|
39
|
+
*)
|
40
|
+
echo "Usage: unicorn_rack {start|stop|restart|reload}"
|
41
|
+
exit 1
|
42
|
+
;;
|
43
|
+
esac
|
44
|
+
done
|
45
|
+
|
46
|
+
exit $RETVAL
|
47
|
+
|
data/examples/unicorn.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# unicorn -c /path/to/unicorn.rb -e production -D
|
2
|
+
# Unicorn-specific config
|
3
|
+
# Largely borrowed from the Github crew
|
4
|
+
|
5
|
+
app_dir = '/www/campaign_link'
|
6
|
+
worker_processes (ENV['RACK_ENV'] == 'production' ? 6 : 2)
|
7
|
+
|
8
|
+
# Restart any workers that haven't responded in 30 seconds
|
9
|
+
timeout 30
|
10
|
+
|
11
|
+
# Load the Rack app into the master before forking workers
|
12
|
+
# for super-fast worker spawn times
|
13
|
+
preload_app true
|
14
|
+
|
15
|
+
# Listen on a Unix data socket
|
16
|
+
listen 'unix:' + app_dir + '/tmp/sockets/unicorn.sock', :backlog => 2048
|
17
|
+
|
18
|
+
##
|
19
|
+
# REE
|
20
|
+
# http://www.rubyenterpriseedition.com/faq.html#adapt_apps_for_cow
|
21
|
+
if GC.respond_to?(:copy_on_write_friendly=)
|
22
|
+
GC.copy_on_write_friendly = true
|
23
|
+
end
|
24
|
+
|
25
|
+
before_fork do |server, worker|
|
26
|
+
##
|
27
|
+
# When sent a USR2, Unicorn will suffix its pidfile with .oldbin and
|
28
|
+
# immediately start loading up a new version of itself (loaded with a new
|
29
|
+
# version of our app). When this new Unicorn is completely loaded
|
30
|
+
# it will begin spawning workers. The first worker spawned will check to
|
31
|
+
# see if an .oldbin pidfile exists. If so, this means we've just booted up
|
32
|
+
# a new Unicorn and need to tell the old one that it can now die. To do so
|
33
|
+
# we send it a QUIT.
|
34
|
+
#
|
35
|
+
# Using this method we get 0 downtime deploys.
|
36
|
+
|
37
|
+
old_pid = app_dir + '/tmp/pids/unicorn.pid.oldbin'
|
38
|
+
if File.exists?(old_pid) && server.pid != old_pid
|
39
|
+
begin
|
40
|
+
Process.kill("QUIT", File.read(old_pid).to_i)
|
41
|
+
rescue Errno::ENOENT, Errno::ESRCH
|
42
|
+
# someone else did our job for us
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
after_fork do |server, worker|
|
48
|
+
##
|
49
|
+
# Unicorn master is started as root, which is fine, but let's
|
50
|
+
# drop the workers to mongrel:mongrel (or whatever you like...)
|
51
|
+
begin
|
52
|
+
uid, gid = Process.euid, Process.egid
|
53
|
+
user, group = 'mongrel', 'mongrel'
|
54
|
+
target_uid = Etc.getpwnam(user).uid
|
55
|
+
target_gid = Etc.getgrnam(group).gid
|
56
|
+
worker.tmp.chown(target_uid, target_gid)
|
57
|
+
if uid != target_uid || gid != target_gid
|
58
|
+
Process.initgroups(user, target_gid)
|
59
|
+
Process::GID.change_privilege(target_gid)
|
60
|
+
Process::UID.change_privilege(target_uid)
|
61
|
+
end
|
62
|
+
rescue => e
|
63
|
+
if ENV['RACK_ENV'] == 'development'
|
64
|
+
STDERR.puts "couldn't change user, oh well"
|
65
|
+
else
|
66
|
+
raise e
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 3
|
9
|
+
version: 0.0.3
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Billy Gray
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-06-
|
17
|
+
date: 2010-06-14 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -43,6 +43,10 @@ files:
|
|
43
43
|
- README.textile
|
44
44
|
- Rakefile
|
45
45
|
- lib/rack/zetetic/campaign_link.rb
|
46
|
+
- examples/campaigns.yml
|
47
|
+
- examples/config.ru
|
48
|
+
- examples/initscript
|
49
|
+
- examples/unicorn.rb
|
46
50
|
has_rdoc: true
|
47
51
|
homepage: http://github.com/billymeltdown/rack-campaign
|
48
52
|
licenses: []
|