recapi 0.1.9 → 0.1.10
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.
- checksums.yaml +4 -4
- data/README.md +11 -2
- data/lib/recapi.rb +9 -4
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e9d8c7e28e6929bfef64625ac5ba48ba5bec683d27b3d4c91646b67f189cadeb
|
|
4
|
+
data.tar.gz: b17b8ad7945fac43147ce43aca7cd27a1b62105a155fdc5ce15d8eccc7e6fca9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 01a65170536dc4f5f33596f509fc7102670ba72a566954b1443d7d4dc29f01137206c4a3b3c49822c4bf85bc6b3200751655a49480a2afa46fe0e10ba3fa45e5
|
|
7
|
+
data.tar.gz: d6d63d879a0eed194f410983abef9770b3296606184cf822a4824c56c2a0dd5a6350922595af45257c9ddf3bb3905be35de694ba9f230a9cc2d5d7a7b6676e7e
|
data/README.md
CHANGED
|
@@ -30,7 +30,7 @@ line with your address): save it as `lib/recapi.rb` and
|
|
|
30
30
|
`require Rails.root.join("lib/recapi").to_s` instead.
|
|
31
31
|
|
|
32
32
|
```sh
|
|
33
|
-
curl -fLo lib/recapi.rb https://api.<your-domain>/sdk/ruby/recapi-0.1.
|
|
33
|
+
curl -fLo lib/recapi.rb https://api.<your-domain>/sdk/ruby/recapi-0.1.10.rb
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
## Quick start
|
|
@@ -74,7 +74,7 @@ and a log line.
|
|
|
74
74
|
|---|---|
|
|
75
75
|
| `track(item_id, level, user_id:, anon_id:, recommendation_id:)` | Records an interaction: `level` -10 to 10 or `:view` (3), `:cart` (5), `:purchase` (10), `:reject` (-10: never recommend the item to this user again until a positive event on it). The history changes at once; a background thread sends the event within 2 s (at once when a batch of 1,000 is full). An `item_id` the API would refuse (1-256 bytes of UTF-8, no control character; also `nil`, an Array or a Hash) drops the event with a log line: nothing raises, and the other events are sent as usual. A bad `level`, `user_id`, `anon_id` or `recommendation_id` still raises `ArgumentError`. |
|
|
76
76
|
| `flush` | Sends the queued events now, with retries (end of a job). A network error, 429 or 5xx is retried 3 times (0.5 s, 1 s, 2 s with jitter, or the `Retry-After`, at most 8 s), then the events stay queued and the sender backs off up to a minute; any other error drops them (logged). |
|
|
77
|
-
| `close` | Stops the sender and sends what is queued, one try per batch. It runs by itself at exit. |
|
|
77
|
+
| `close` | Stops the sender and sends what is queued, one try per batch. It runs by itself at exit, also for a classic Sinatra app (`ruby app.rb`), whose server runs from its own exit hook. Don't `track` while such an app loads, before its server starts: the client then closes before the first request, and every later `track` is sent on the page's thread. |
|
|
78
78
|
| `recommend(user_id:, anon_id:, count:, placement:, tags_any:, tags_all:, exclude:, context_item_id:, discovery:)` | A `Recapi::Recommendations` (`recommendation_id`, `fallback?`, `items`). At most 1.5 s; on a network error, timeout, 5xx or 429 it returns popular items (`fallback?`, no id), or no item when those fail too: hide the slot; on a 401 or 403 no item at once. A `context_item_id` the API would refuse (also an Array or a Hash, as `params[:id]` gives for `?id[]=a`) isn't sent: you get the same popular list and a log line, with no recommendation request. Any other failure (a bad request, a reply that isn't the API's) raises. |
|
|
79
79
|
| `identify(anon_id, user_id)` | At login: the visitor's history and shown items become the user's. The user's first restore from recapi then leaves that visitor's browsing out, so it doesn't count twice. |
|
|
80
80
|
| `popular(count:, tags_any:, tags_all:)` | Popular items, for pages without a user. On a network error, timeout, 5xx, 429, 401 or 403: an empty list and a log line. Other failures as in `recommend`. |
|
|
@@ -122,6 +122,15 @@ and logs one line at start:
|
|
|
122
122
|
so a visitor who never returns stays on disk (about 8 KB each): run
|
|
123
123
|
`Rails.cache.cleanup` on a schedule, or leave `store:` out.
|
|
124
124
|
|
|
125
|
+
## Changes
|
|
126
|
+
|
|
127
|
+
- 2026-11-05: version 0.1.10. `track` stays queued and in the background in a
|
|
128
|
+
classic Sinatra app
|
|
129
|
+
(`ruby app.rb`). The exit hook used to close the client before the server
|
|
130
|
+
started, so every event was sent on the page's thread, and a hung API
|
|
131
|
+
stalled each page for 5 s. The hook now starts with the sender, at the first
|
|
132
|
+
`track`.
|
|
133
|
+
|
|
125
134
|
## Development
|
|
126
135
|
|
|
127
136
|
`../../scripts/ruby.sh -w test/run.rb [filter]` runs the tests (`make
|
data/lib/recapi.rb
CHANGED
|
@@ -25,7 +25,7 @@ rescue LoadError
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
module Recapi
|
|
28
|
-
VERSION = "0.1.
|
|
28
|
+
VERSION = "0.1.10"
|
|
29
29
|
|
|
30
30
|
# Decayed user history, exactly as docs/history-spec.md (times in unix ms).
|
|
31
31
|
# A port of sdk/python's history.py, snapshot merging included.
|
|
@@ -433,8 +433,8 @@ module Recapi
|
|
|
433
433
|
TIMEOUT_ERRORS = [Net::OpenTimeout, Net::ReadTimeout, Net::WriteTimeout].freeze
|
|
434
434
|
# A connection the server closed while idle fails this way, before any reply.
|
|
435
435
|
STALE_ERRORS = [EOFError, Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED].freeze
|
|
436
|
-
# Made here, not in
|
|
437
|
-
#
|
|
436
|
+
# Made here, not in enqueue, whose block would hold the client through self:
|
|
437
|
+
# the weak reference lets a dropped client be collected.
|
|
438
438
|
CLOSE_AT_EXIT = lambda do |ref|
|
|
439
439
|
at_exit do
|
|
440
440
|
ref.__getobj__.close
|
|
@@ -480,7 +480,6 @@ module Recapi
|
|
|
480
480
|
@sleeper = method(:wait)
|
|
481
481
|
@random = -> { rand }
|
|
482
482
|
init_threading
|
|
483
|
-
CLOSE_AT_EXIT.call(WeakRef.new(self))
|
|
484
483
|
end
|
|
485
484
|
|
|
486
485
|
# Records an interaction: the user's history changes at once, the event
|
|
@@ -817,6 +816,12 @@ module Recapi
|
|
|
817
816
|
@thread = Thread.new { run }
|
|
818
817
|
@thread.name = "recapi-sender"
|
|
819
818
|
@thread.report_on_exception = false
|
|
819
|
+
# Here, not in initialize: Sinatra's classic mode serves from its own
|
|
820
|
+
# at_exit, and exit hooks run last registered first, so a hook from
|
|
821
|
+
# the app's load would close the client before the first request.
|
|
822
|
+
# One registered while that server runs goes after the server ends.
|
|
823
|
+
# A forked worker starts its own sender, so it gets its own hook too.
|
|
824
|
+
CLOSE_AT_EXIT.call(WeakRef.new(self))
|
|
820
825
|
end
|
|
821
826
|
@queue << event
|
|
822
827
|
drop_overflow if @queue.size > MAX_QUEUE
|