fast_curl 0.4.0 → 0.5.1
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 +56 -12
- data/ext/fast_curl/fast_curl.c +822 -193
- data/lib/fast_curl/version.rb +1 -1
- data/lib/fast_curl.rb +31 -16
- metadata +3 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e0c5dac84b62da99fa420dc28437ca3284ddd4f73fd970c7730df3c8a2a7ba5b
|
|
4
|
+
data.tar.gz: 7455385e6a1b1c76467e67909bb252a70a6eac465846aacdf988d9e934fb7d79
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5f5b3c2c3797436d23ec37e9f2997c340a5e50b05a4ef9dc82a699093b01fc7a3097c720e14adba1fe6ad3e132e29d90893e01c4bd8a81fbdde3043b9067a727
|
|
7
|
+
data.tar.gz: 5a990531123a9bd72ccc082a5076a5dd1f6eed90f455e92c77c336be33ed964f3ad9a6cef3d59e6322cf378223399505edcaa6d27dd7a0619d71f5c600870bba
|
data/README.md
CHANGED
|
@@ -8,6 +8,7 @@ Ultra-fast parallel HTTP client for Ruby. C extension built on libcurl `curl_mul
|
|
|
8
8
|
- **GVL release** — `rb_thread_call_without_gvl` during I/O, other Ruby threads keep running
|
|
9
9
|
- **Fiber scheduler compatible** — works inside `Async do ... end` without blocking other fibers
|
|
10
10
|
- **Three modes**: execute (all), first_execute (first N), stream_execute (yield as ready)
|
|
11
|
+
- **Lazy Enumerable sources** — bounded request preparation for large or infinite streams
|
|
11
12
|
- **Zero dependencies** — only libcurl (available everywhere)
|
|
12
13
|
|
|
13
14
|
## Installation
|
|
@@ -81,6 +82,34 @@ Query parameters can be passed separately:
|
|
|
81
82
|
FastCurl.get([{ url: "https://api.example.com/search", params: { q: "ruby", page: 2 } }])
|
|
82
83
|
```
|
|
83
84
|
|
|
85
|
+
### Lazy / bounded Enumerable sources
|
|
86
|
+
|
|
87
|
+
`Array` keeps the existing fast path. Any other object responding to `#each` is
|
|
88
|
+
consumed lazily, so large request sets do not need to be materialized first:
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
requests = Enumerator.new do |y|
|
|
92
|
+
1_000_000.times do |i|
|
|
93
|
+
y << { url: "https://api.example.com/items/#{i}" }
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
FastCurl.stream_get(requests, connections: 20, buffer: 20) do |index, response|
|
|
98
|
+
puts "#{index}: #{response[:status]}"
|
|
99
|
+
end
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
For lazy sources, at most `connections + buffer` requests are retained by
|
|
103
|
+
`fast_curl`. The source itself may have produced one additional item before
|
|
104
|
+
backpressure is applied, so a generator can observe a maximum look-ahead of
|
|
105
|
+
`connections + buffer + 1`. `buffer` defaults to `connections`.
|
|
106
|
+
|
|
107
|
+
`FastCurl.get` still returns all results in input order, so its result array is
|
|
108
|
+
necessarily O(N). Use `stream_get` when the whole pipeline must stay bounded.
|
|
109
|
+
Source exceptions and stream callback exceptions unwind the native multi loop
|
|
110
|
+
and release active curl handles; an `ensure` in the source is also unwound on
|
|
111
|
+
early completed `first_*` calls.
|
|
112
|
+
|
|
84
113
|
### First N responses (cancel the rest)
|
|
85
114
|
|
|
86
115
|
```ruby
|
|
@@ -91,6 +120,19 @@ result = FastCurl.first_get([
|
|
|
91
120
|
], count: 1)
|
|
92
121
|
```
|
|
93
122
|
|
|
123
|
+
`accept:` can keep the race running until a response satisfies a predicate:
|
|
124
|
+
|
|
125
|
+
```ruby
|
|
126
|
+
result = FastCurl.first_get(
|
|
127
|
+
mirrors,
|
|
128
|
+
connections: 3,
|
|
129
|
+
accept: ->(response) { response[:status].between?(200, 299) }
|
|
130
|
+
)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The predicate receives the response Hash. Rejected responses do not count
|
|
134
|
+
toward `count`.
|
|
135
|
+
|
|
94
136
|
### Stream responses as they arrive
|
|
95
137
|
|
|
96
138
|
```ruby
|
|
@@ -195,6 +237,7 @@ folded and is **always** an Array, even for a single cookie.
|
|
|
195
237
|
| Option | Default | Description |
|
|
196
238
|
|---|---|---|
|
|
197
239
|
| `connections` | 20 | Max parallel connections |
|
|
240
|
+
| `buffer` | `connections` | Lazy-source prefetch window; ignored for already-materialized Arrays |
|
|
198
241
|
| `timeout` | 30 | Timeout for a single attempt, in seconds (1-300) |
|
|
199
242
|
| `connect_timeout` | 10000 | Connection phase timeout, in milliseconds |
|
|
200
243
|
| `total_timeout` | none | Wall-clock budget for the whole call, in milliseconds |
|
|
@@ -204,6 +247,7 @@ folded and is **always** an Array, even for a single cookie.
|
|
|
204
247
|
| `retry_non_idempotent` | false | Also retry POST and PATCH |
|
|
205
248
|
| `follow_redirects` | true | Follow `Location` headers |
|
|
206
249
|
| `max_redirects` | 5 | Redirect limit (0-100) |
|
|
250
|
+
| `accept` | none | `first_*` predicate receiving the response Hash |
|
|
207
251
|
|
|
208
252
|
DNS results and TLS sessions are cached process-wide, so repeated calls to the
|
|
209
253
|
same host skip resolution and can resume TLS. TCP connections are pooled only
|
|
@@ -234,27 +278,27 @@ grows linearly while parallel clients stay near ~1s plus network overhead.
|
|
|
234
278
|
|
|
235
279
|
| Scenario | Net::HTTP sequential | fast_curl (thread) | fast_curl (fiber/Async) | Async::HTTP::Internet |
|
|
236
280
|
|---------------------------------|---------------------:|-------------------:|------------------------:|----------------------:|
|
|
237
|
-
| 4 requests × 1s, conn=4 |
|
|
238
|
-
| 10 requests × 1s, conn=10 |
|
|
239
|
-
| 20 requests × 1s, conn=5 |
|
|
240
|
-
| 200 requests × 1s, conn=20 | — |
|
|
281
|
+
| 4 requests × 1s, conn=4 | 5.82s | 1.68s | 1.65s | 1.93s |
|
|
282
|
+
| 10 requests × 1s, conn=10 | 17.51s | 1.70s | 1.68s | 1.89s |
|
|
283
|
+
| 20 requests × 1s, conn=5 | 34.66s | 5.69s | 6.71s | 5.79s |
|
|
284
|
+
| 200 requests × 1s, conn=20 | — | 14.29s | 14.29s | 7.27s |
|
|
241
285
|
|
|
242
286
|
### Speedup vs Net::HTTP (median)
|
|
243
287
|
|
|
244
288
|
| Scenario | fast_curl (thread) | fast_curl (fiber) | Async::HTTP |
|
|
245
289
|
|-----------------------------------|-------------------:|------------------:|------------:|
|
|
246
|
-
| 4 requests × 1s | **3.5x** | 3.
|
|
247
|
-
| 10 requests × 1s |
|
|
248
|
-
| 20 requests × 1s (queued, conn=5) |
|
|
290
|
+
| 4 requests × 1s | **3.5x** | 3.5x | 3.0x |
|
|
291
|
+
| 10 requests × 1s | **10.3x** | 10.4x | 9.2x |
|
|
292
|
+
| 20 requests × 1s (queued, conn=5) | **6.1x** | 5.2x | 6.0x |
|
|
249
293
|
|
|
250
294
|
### Memory & allocations per request batch (lower is better)
|
|
251
295
|
|
|
252
296
|
| Scenario | fast_curl (thread) allocated | fast_curl (fiber) allocated | Async::HTTP allocated |
|
|
253
297
|
|---------------------------------|-----------------------------:|----------------------------:|----------------------:|
|
|
254
|
-
| 4 requests × 1s | **
|
|
255
|
-
| 10 requests × 1s | **
|
|
256
|
-
| 20 requests × 1s, conn=5 | **
|
|
257
|
-
| 200 requests × 1s, conn=20 | **5,
|
|
298
|
+
| 4 requests × 1s | **125 obj** | 179 obj | 1,921 obj |
|
|
299
|
+
| 10 requests × 1s | **281 obj** | 335 obj | 3,344 obj |
|
|
300
|
+
| 20 requests × 1s, conn=5 | **541 obj** | 595 obj | 5,898 obj |
|
|
301
|
+
| 200 requests × 1s, conn=20 | **5,222 obj** | 5,275 obj | 50,534 obj |
|
|
258
302
|
|
|
259
303
|
Ruby heap delta stays near zero across all scenarios for fast_curl — most allocation
|
|
260
304
|
happens in C, not on the Ruby heap.
|
|
@@ -263,7 +307,7 @@ happens in C, not on the Ruby heap.
|
|
|
263
307
|
|
|
264
308
|
| Scenario | Time |
|
|
265
309
|
|--------------------------------------------------------------|------:|
|
|
266
|
-
| 4 mixed requests (404, 500, DNS fail, 30s delay), timeout=2s |
|
|
310
|
+
| 4 mixed requests (404, 500, DNS fail, 30s delay), timeout=2s | 0.68s |
|
|
267
311
|
|
|
268
312
|
Bounded by `timeout=2s` rather than by the slow request.
|
|
269
313
|
|