mixpanel 0.7.0 → 0.8.0

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.
@@ -33,7 +33,7 @@ In your application_controller class add a method to instance mixpanel.
33
33
  before_filter :initialize_mixpanel
34
34
 
35
35
  def initialize_mixpanel
36
- @mixpanel = Mixpanel.new("YOUR_MIXPANEL_API_TOKEN", request.env)
36
+ @mixpanel = Mixpanel.new("YOUR_MIXPANEL_API_TOKEN", request.env, true)
37
37
  end
38
38
 
39
39
  Then in each request you want to track some event you can use:
@@ -54,12 +54,13 @@ To execute any javascript API call
54
54
 
55
55
  == Notes
56
56
 
57
- It is strongly recommended to call Mixpanel#track_event using an async lib
58
- like delayed job or similar, otherwise you will delay your server responses
59
- with mixpanel responses.
57
+ There are two forms of async operation:
58
+ * Using MixpanelMiddleware, events are queued via Mixpanel#append_event and inserted into a JavaScript block within the HTML response.
59
+ * Using Mixpanel.new(…, …, true), events are sent to a subprocess via a pipe and the sub process which asynchronously send events to Mixpanel. This process uses a single thread to upload events, and may start dropping events if your application generates them at a very high rate.
60
60
 
61
61
  == Collaborators and Maintainers
62
62
 
63
63
  * {Alvaro Gil}[https://github.com/zevarito] (Author)
64
64
  * {Nathan Baxter}[https://github.com/LogicWolfe]
65
65
  * {Jake Mallory}[https://github.com/tinomen]
66
+ * {Logan Bowers}[https://github.com/loganb]
@@ -2,10 +2,13 @@ require "open-uri"
2
2
  require 'base64'
3
3
  require 'json'
4
4
 
5
+ require 'thread'
6
+
5
7
  class Mixpanel
6
- def initialize(token, env)
8
+ def initialize(token, env, async = false)
7
9
  @token = token
8
10
  @env = env
11
+ @async = async
9
12
  clear_queue
10
13
  end
11
14
 
@@ -33,6 +36,35 @@ class Mixpanel
33
36
  def clear_queue
34
37
  @env["mixpanel_events"] = []
35
38
  end
39
+
40
+ class <<self
41
+ WORKER_MUTEX = Mutex.new
42
+
43
+ def worker
44
+ WORKER_MUTEX.synchronize do
45
+ @worker || (@worker = IO.popen(self.cmd, 'w'))
46
+ end
47
+ end
48
+
49
+ def dispose_worker(w)
50
+ WORKER_MUTEX.synchronize do
51
+ if(@worker == w)
52
+ @worker = nil
53
+ w.close
54
+ end
55
+ end
56
+ end
57
+
58
+ def cmd
59
+ @cmd || begin
60
+ require 'escape'
61
+ require 'rbconfig'
62
+ interpreter = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['RUBY_SO_NAME'])
63
+ subprocess = File.join(File.dirname(__FILE__), 'mixpanel_subprocess.rb')
64
+ @cmd = Escape.shell_command([interpreter, subprocess])
65
+ end
66
+ end
67
+ end
36
68
 
37
69
  private
38
70
 
@@ -44,7 +76,17 @@ class Mixpanel
44
76
  data = Base64.encode64(JSON.generate(params)).gsub(/\n/,'')
45
77
  url = "http://api.mixpanel.com/track/?data=#{data}"
46
78
 
47
- open(url).read
79
+ if(@async)
80
+ w = Mixpanel.worker
81
+ begin
82
+ url << "\n"
83
+ w.write(url)
84
+ rescue Errno::EPIPE => e
85
+ Mixpanel.dispose_worker(w)
86
+ end
87
+ else
88
+ open(url).read
89
+ end
48
90
  end
49
91
 
50
92
  def build_event(event, properties)
@@ -0,0 +1,30 @@
1
+
2
+ require 'rubygems'
3
+ require 'mixpanel'
4
+ require 'open-uri'
5
+
6
+ require 'thread'
7
+
8
+ class Mixpanel::Subprocess
9
+ Q = Queue.new
10
+ ENDMARKER = Object.new
11
+
12
+ Thread.abort_on_exception = true
13
+ producer = Thread.new do
14
+ STDIN.each_line() do |url|
15
+ STDERR.puts("Dropped: #{url}") && next if Q.length > 10000
16
+ Q << url
17
+ end
18
+ Q << ENDMARKER
19
+ end
20
+
21
+ loop do
22
+ url = Q.pop
23
+ break if(url == ENDMARKER)
24
+ url.chomp!
25
+ next if(url.empty?) #for testing
26
+
27
+ open(url).read
28
+ end
29
+ producer.join
30
+ end
@@ -2,7 +2,7 @@ files = ['README.rdoc', 'LICENSE', 'Rakefile', 'mixpanel.gemspec', '{spec,lib}/*
2
2
 
3
3
  spec = Gem::Specification.new do |s|
4
4
  s.name = "mixpanel"
5
- s.version = "0.7.0"
5
+ s.version = "0.8.0"
6
6
  s.rubyforge_project = "mixpanel"
7
7
  s.description = "Simple lib to track events in Mixpanel service. It can be used in any rack based framework."
8
8
  s.author = "Alvaro Gil"
@@ -16,6 +16,7 @@ spec = Gem::Specification.new do |s|
16
16
  s.extra_rdoc_files = ["README.rdoc"]
17
17
  s.add_dependency 'json'
18
18
  s.add_dependency 'rack'
19
+ s.add_dependency 'escape'
19
20
  s.add_development_dependency 'rspec'
20
21
  s.add_development_dependency 'rack-test'
21
22
  s.add_development_dependency 'fakeweb'
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Mixpanel do
4
- before do
4
+ before(:each) do
5
5
  @mixpanel = Mixpanel.new(MIX_PANEL_TOKEN, @env = {"REMOTE_ADDR" => "127.0.0.1"})
6
6
  end
7
7
 
@@ -82,4 +82,32 @@ describe Mixpanel do
82
82
  end
83
83
  end
84
84
  end
85
+
86
+ context "Accessing Mixpanel asynchronously" do
87
+ it "should open a subprocess successfully" do
88
+ w = Mixpanel.worker
89
+ w.should == Mixpanel.worker
90
+ end
91
+
92
+ it "should be able to write lines to the worker" do
93
+ w = Mixpanel.worker
94
+
95
+ #On most systems this will exceed the pipe buffer size
96
+ 8.times do
97
+ 9000.times do
98
+ w.write("\n")
99
+ end
100
+ sleep 0.1
101
+ end
102
+ end
103
+
104
+ it "should dispose of a worker" do
105
+ w = Mixpanel.worker
106
+ Mixpanel.dispose_worker(w)
107
+
108
+ w.closed?.should == true
109
+ w2 = Mixpanel.worker
110
+ w2.should_not == w
111
+ end
112
+ end
85
113
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mixpanel
3
3
  version: !ruby/object:Gem::Version
4
- hash: 3
4
+ hash: 63
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 7
8
+ - 8
9
9
  - 0
10
- version: 0.7.0
10
+ version: 0.8.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Alvaro Gil
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-11-26 00:00:00 -02:00
18
+ date: 2011-01-25 00:00:00 -02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -47,7 +47,7 @@ dependencies:
47
47
  type: :runtime
48
48
  version_requirements: *id002
49
49
  - !ruby/object:Gem::Dependency
50
- name: rspec
50
+ name: escape
51
51
  prerelease: false
52
52
  requirement: &id003 !ruby/object:Gem::Requirement
53
53
  none: false
@@ -58,10 +58,10 @@ dependencies:
58
58
  segments:
59
59
  - 0
60
60
  version: "0"
61
- type: :development
61
+ type: :runtime
62
62
  version_requirements: *id003
63
63
  - !ruby/object:Gem::Dependency
64
- name: rack-test
64
+ name: rspec
65
65
  prerelease: false
66
66
  requirement: &id004 !ruby/object:Gem::Requirement
67
67
  none: false
@@ -75,7 +75,7 @@ dependencies:
75
75
  type: :development
76
76
  version_requirements: *id004
77
77
  - !ruby/object:Gem::Dependency
78
- name: fakeweb
78
+ name: rack-test
79
79
  prerelease: false
80
80
  requirement: &id005 !ruby/object:Gem::Requirement
81
81
  none: false
@@ -89,7 +89,7 @@ dependencies:
89
89
  type: :development
90
90
  version_requirements: *id005
91
91
  - !ruby/object:Gem::Dependency
92
- name: nokogiri
92
+ name: fakeweb
93
93
  prerelease: false
94
94
  requirement: &id006 !ruby/object:Gem::Requirement
95
95
  none: false
@@ -102,6 +102,20 @@ dependencies:
102
102
  version: "0"
103
103
  type: :development
104
104
  version_requirements: *id006
105
+ - !ruby/object:Gem::Dependency
106
+ name: nokogiri
107
+ prerelease: false
108
+ requirement: &id007 !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ hash: 3
114
+ segments:
115
+ - 0
116
+ version: "0"
117
+ type: :development
118
+ version_requirements: *id007
105
119
  description: Simple lib to track events in Mixpanel service. It can be used in any rack based framework.
106
120
  email: zevarito@gmail.com
107
121
  executables: []
@@ -121,6 +135,7 @@ files:
121
135
  - spec/support/rack_apps.rb
122
136
  - lib/mixpanel/mixpanel.rb
123
137
  - lib/mixpanel/mixpanel_middleware.rb
138
+ - lib/mixpanel/mixpanel_subprocess.rb
124
139
  - lib/mixpanel.rb
125
140
  has_rdoc: true
126
141
  homepage: http://cuboxsa.com