funnel_http 0.3.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca358cfbd282a397a1e8e4458f00c842deb22b8c3715a57bc26dfa171c0394f5
4
- data.tar.gz: e730cb4d2cc871a82547b6008db1f919243e8102bdd28bfaa95b9838208c38a1
3
+ metadata.gz: 8dc5ca92f2cadd38540d16fefc60846938f645205482549ed6075a151b4bf446
4
+ data.tar.gz: f4d709200e55e657ba73b70c8c7cd0620ba065644f20f6393c24a765a71cbcf8
5
5
  SHA512:
6
- metadata.gz: 5b567c0a370a7cdba78948dcb7ab66b97192c9bc227dc2b5da3fc5234fc955cf6e35b22455322a79235fbda3fbe51822765706229c928c5998709aa1808a6bc8
7
- data.tar.gz: e3d5993b8445e7385c51ad410aa4d2e703c9f397129ae01551f1cb3d31cf5dcbc94c713009f02bb980c0c8c53702bb3dc31504f9e03736da472a43ea606fde31
6
+ metadata.gz: 60c7d733ee0cd9cf43ddb1b705ae69b8b9cb97c32eb6ad62e6d170202760307aaa0caa508128674cd4d2a1d68b78d0f985cad6a5cd15ad138e68446b6e09d171
7
+ data.tar.gz: 317bb2a84a2bb0e89ccfc92def4669a58f60a107e0756959a3298aa3b2ad0135bbb72db27bfd43825895c962f94c4ab4554e92d7877a2f5d9bd2dc9e3581d660
data/.golangci.yml CHANGED
@@ -1,12 +1,9 @@
1
1
  linters-settings:
2
- gofmt:
3
2
  revive:
4
3
  rules:
5
4
  - name: exported
6
5
  arguments:
7
6
  - disableStutteringCheck
8
- testifylint:
9
- wrapcheck:
10
7
 
11
8
  linters:
12
9
  enable:
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  ## [Unreleased]
2
- [full changelog](http://github.com/sue445/funnel_http/compare/v0.3.0...main)
2
+ [full changelog](http://github.com/sue445/funnel_http/compare/v0.3.1...main)
3
+
4
+ ## [0.3.1](https://github.com/sue445/funnel_http/releases/tag/v0.3.1) - 2025-03-12
5
+ [full changelog](http://github.com/sue445/funnel_http/compare/v0.3.0...v0.3.1)
6
+
7
+ * Diet gem
8
+ * https://github.com/sue445/funnel_http/pull/66
9
+ * Tweak gem description
10
+ * https://github.com/sue445/funnel_http/pull/68
3
11
 
4
12
  ## [0.3.0](https://github.com/sue445/funnel_http/releases/tag/v0.3.0) - 2025-01-12
5
13
  [full changelog](http://github.com/sue445/funnel_http/compare/v0.2.0...v0.3.0)
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # FunnelHttp
2
- Perform HTTP requests in parallel
2
+ Perform HTTP requests in parallel with goroutine
3
3
 
4
4
  [![Gem Version](https://badge.fury.io/rb/funnel_http.svg)](https://badge.fury.io/rb/funnel_http)
5
5
  [![build](https://github.com/sue445/funnel_http/actions/workflows/build.yml/badge.svg)](https://github.com/sue445/funnel_http/actions/workflows/build.yml)
@@ -1,13 +1,15 @@
1
1
  module github.com/sue445/funnel_http
2
2
 
3
- go 1.23
3
+ go 1.23.0
4
+
5
+ toolchain go1.24.0
4
6
 
5
7
  require (
6
8
  github.com/cockroachdb/errors v1.11.3
7
9
  github.com/jarcoal/httpmock v1.3.1
8
- github.com/ruby-go-gem/go-gem-wrapper v0.6.0
10
+ github.com/ruby-go-gem/go-gem-wrapper v0.7.2
9
11
  github.com/stretchr/testify v1.10.0
10
- golang.org/x/sync v0.10.0
12
+ golang.org/x/sync v0.12.0
11
13
  )
12
14
 
13
15
  require (
@@ -34,10 +34,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
34
34
  github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
35
35
  github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
36
36
  github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
37
- github.com/ruby-go-gem/go-gem-wrapper v0.5.1 h1:TFGH/eOJl0uYzYMwrcLbZxXNQiQbQjCq/VLXyRk1HRM=
38
- github.com/ruby-go-gem/go-gem-wrapper v0.5.1/go.mod h1:k2k+LziSCMxNYP4J9/9v90xdU6zlU1DJpJDTU6oJhHE=
39
- github.com/ruby-go-gem/go-gem-wrapper v0.6.0 h1:WFu2Cj/uzKAOemsrCo4P6vsdOgB5yesrrJtAqvLkAso=
40
- github.com/ruby-go-gem/go-gem-wrapper v0.6.0/go.mod h1:k2k+LziSCMxNYP4J9/9v90xdU6zlU1DJpJDTU6oJhHE=
37
+ github.com/ruby-go-gem/go-gem-wrapper v0.7.2 h1:Hf7bA5TD/UjJTccTwsbBJWnjpBvcQWAzX50tv9++4+o=
38
+ github.com/ruby-go-gem/go-gem-wrapper v0.7.2/go.mod h1:k2k+LziSCMxNYP4J9/9v90xdU6zlU1DJpJDTU6oJhHE=
41
39
  github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
42
40
  github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
43
41
  github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -54,8 +52,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
54
52
  golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
55
53
  golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
56
54
  golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
57
- golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
58
- golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
55
+ golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
56
+ golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
59
57
  golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
60
58
  golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
61
59
  golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FunnelHttp
4
- VERSION = "0.3.0"
4
+ VERSION = "0.3.1"
5
5
  end
@@ -2,9 +2,13 @@
2
2
  path: ".gem_rbs_collection"
3
3
  gems:
4
4
  - name: base64
5
- version: '0'
5
+ version: '0.1'
6
6
  source:
7
- type: stdlib
7
+ type: git
8
+ name: ruby/gem_rbs_collection
9
+ revision: 7c22ddc3de54df89ebb2546c9dcb1c1498c8154a
10
+ remote: https://github.com/ruby/gem_rbs_collection.git
11
+ repo_dir: gems
8
12
  - name: cgi
9
13
  version: '0'
10
14
  source:
@@ -14,7 +18,7 @@ gems:
14
18
  source:
15
19
  type: git
16
20
  name: ruby/gem_rbs_collection
17
- revision: 7ff8cf6ab2759cb1d0fb2ca8d6c1f8ccab2c605c
21
+ revision: 7c22ddc3de54df89ebb2546c9dcb1c1498c8154a
18
22
  remote: https://github.com/ruby/gem_rbs_collection.git
19
23
  repo_dir: gems
20
24
  - name: fileutils
@@ -34,7 +38,7 @@ gems:
34
38
  source:
35
39
  type: git
36
40
  name: ruby/gem_rbs_collection
37
- revision: 7ff8cf6ab2759cb1d0fb2ca8d6c1f8ccab2c605c
41
+ revision: 7c22ddc3de54df89ebb2546c9dcb1c1498c8154a
38
42
  remote: https://github.com/ruby/gem_rbs_collection.git
39
43
  repo_dir: gems
40
44
  - name: rack
@@ -42,7 +46,7 @@ gems:
42
46
  source:
43
47
  type: git
44
48
  name: ruby/gem_rbs_collection
45
- revision: 7ff8cf6ab2759cb1d0fb2ca8d6c1f8ccab2c605c
49
+ revision: 7c22ddc3de54df89ebb2546c9dcb1c1498c8154a
46
50
  remote: https://github.com/ruby/gem_rbs_collection.git
47
51
  repo_dir: gems
48
52
  - name: rake
@@ -50,7 +54,7 @@ gems:
50
54
  source:
51
55
  type: git
52
56
  name: ruby/gem_rbs_collection
53
- revision: 7ff8cf6ab2759cb1d0fb2ca8d6c1f8ccab2c605c
57
+ revision: 7c22ddc3de54df89ebb2546c9dcb1c1498c8154a
54
58
  remote: https://github.com/ruby/gem_rbs_collection.git
55
59
  repo_dir: gems
56
60
  - name: sinatra
@@ -58,7 +62,7 @@ gems:
58
62
  source:
59
63
  type: git
60
64
  name: ruby/gem_rbs_collection
61
- revision: 7ff8cf6ab2759cb1d0fb2ca8d6c1f8ccab2c605c
65
+ revision: 7c22ddc3de54df89ebb2546c9dcb1c1498c8154a
62
66
  remote: https://github.com/ruby/gem_rbs_collection.git
63
67
  repo_dir: gems
64
68
  - name: stringio
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: funnel_http
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - sue445
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-01-12 00:00:00.000000000 Z
10
+ date: 2025-03-12 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: go_gem
@@ -191,7 +191,7 @@ dependencies:
191
191
  - - ">="
192
192
  - !ruby/object:Gem::Version
193
193
  version: '0'
194
- description: Perform HTTP requests in parallel
194
+ description: Perform HTTP requests in parallel with goroutine
195
195
  email:
196
196
  - sue445@sue445.net
197
197
  executables: []
@@ -207,11 +207,6 @@ files:
207
207
  - README.md
208
208
  - Rakefile
209
209
  - Steepfile
210
- - benchmark/README.md
211
- - benchmark/benchmark.rb
212
- - benchmark/compose.yml
213
- - benchmark/html/index.html
214
- - benchmark/nginx.conf
215
210
  - ext/funnel_http/extconf.rb
216
211
  - ext/funnel_http/funnel_http.c
217
212
  - ext/funnel_http/funnel_http.go
@@ -219,7 +214,6 @@ files:
219
214
  - ext/funnel_http/go.mod
220
215
  - ext/funnel_http/go.sum
221
216
  - ext/funnel_http/run_requests.go
222
- - ext/funnel_http/run_requests_test.go
223
217
  - lib/funnel_http.rb
224
218
  - lib/funnel_http/client.rb
225
219
  - lib/funnel_http/ext.rb
@@ -254,5 +248,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
254
248
  requirements: []
255
249
  rubygems_version: 3.6.2
256
250
  specification_version: 4
257
- summary: Perform HTTP requests in parallel
251
+ summary: Perform HTTP requests in parallel with goroutine
258
252
  test_files: []
data/benchmark/README.md DELETED
@@ -1,32 +0,0 @@
1
- # benchmark for funnel_http
2
- ## Usage
3
- ```bash
4
- docker compose up --build
5
- ```
6
-
7
- ```bash
8
- bundle exec ruby benchmark.rb
9
- ```
10
-
11
- ## Report
12
- ```
13
- Warming up --------------------------------------
14
- FunnelHttp::Client#perform
15
- 2.000 i/100ms
16
- Parallel with 4 processes
17
- 1.000 i/100ms
18
- Parallel with 4 threads
19
- 1.000 i/100ms
20
- Calculating -------------------------------------
21
- FunnelHttp::Client#perform
22
- 21.816 (± 4.6%) i/s (45.84 ms/i) - 44.000 in 2.026960s
23
- Parallel with 4 processes
24
- 15.785 (± 6.3%) i/s (63.35 ms/i) - 32.000 in 2.035628s
25
- Parallel with 4 threads
26
- 18.570 (±10.8%) i/s (53.85 ms/i) - 37.000 in 2.008485s
27
-
28
- Comparison:
29
- FunnelHttp::Client#perform: 21.8 i/s
30
- Parallel with 4 threads: 18.6 i/s - 1.17x slower
31
- Parallel with 4 processes: 15.8 i/s - 1.38x slower
32
- ```
@@ -1,61 +0,0 @@
1
- require "benchmark/ips"
2
- require "open-uri"
3
- require "parallel"
4
- require "etc"
5
-
6
- ROOT_DIR = File.expand_path("..", __dir__)
7
-
8
- TEST_SERVER_URL = ENV.fetch("TEST_SERVER_URL") { "http://localhost:8080/" }
9
-
10
- REQUEST_COUNT = 100
11
-
12
- BENCHMARK_CONCURRENCY = (ENV.fetch("BENCHMARK_CONCURRENCY") { 4 }).to_i
13
-
14
- # Build native extension before running benchmark
15
- Dir.chdir(ROOT_DIR) do
16
- system("bundle config set --local path 'vendor/bundle'", exception: true)
17
- system("bundle install", exception: true)
18
- system("bundle exec rake clobber compile", exception: true)
19
- end
20
-
21
- require_relative "../lib/funnel_http"
22
-
23
- # Suppress Ractor warning
24
- $VERBOSE = nil
25
-
26
- system("go version", exception: true)
27
-
28
- requests = Array.new(REQUEST_COUNT, { method: :get, url: TEST_SERVER_URL })
29
-
30
- def fetch_server
31
- URI.parse(TEST_SERVER_URL).open(open_timeout: 90, read_timeout: 90).read
32
- end
33
-
34
- Benchmark.ips do |x|
35
- # x.config(warmup: 1, time: 2)
36
-
37
- x.report("FunnelHttp::Client#perform") do
38
- FunnelHttp::Client.new.perform(requests)
39
- end
40
-
41
- x.report("Parallel with #{BENCHMARK_CONCURRENCY} processes") do
42
- Parallel.each(requests, in_processes: BENCHMARK_CONCURRENCY) do
43
- fetch_server
44
- end
45
- end
46
-
47
- x.report("Parallel with #{BENCHMARK_CONCURRENCY} threads") do
48
- Parallel.each(requests, in_threads: BENCHMARK_CONCURRENCY) do
49
- fetch_server
50
- end
51
- end
52
-
53
- # FIXME: open-uri doesn't work in Ractor
54
- # x.report("Parallel with Ractor") do
55
- # REQUEST_COUNT.times.map do
56
- # Ractor.new { URI.parse("http://localhost:8080/").read }
57
- # end.each(&:take)
58
- # end
59
-
60
- x.compare!
61
- end
@@ -1,8 +0,0 @@
1
- services:
2
- nginx:
3
- image: nginx:latest
4
- ports:
5
- - "8080:80"
6
- volumes:
7
- - ./html:/usr/share/nginx/html
8
- - ./nginx.conf:/etc/nginx/nginx.conf
@@ -1,4 +0,0 @@
1
- <html>
2
- <head></head>
3
- <body>it works</body>
4
- </html>
data/benchmark/nginx.conf DELETED
@@ -1,25 +0,0 @@
1
- worker_processes auto;
2
- worker_rlimit_nofile 12288;
3
-
4
- events {
5
- worker_connections 4096;
6
- }
7
-
8
- http {
9
- include mime.types;
10
- default_type application/octet-stream;
11
-
12
- sendfile on;
13
- keepalive_timeout 65;
14
- access_log off;
15
-
16
- server {
17
- listen 80;
18
- server_name localhost;
19
-
20
- location / {
21
- root /usr/share/nginx/html;
22
- index index.html;
23
- }
24
- }
25
- }
@@ -1,204 +0,0 @@
1
- package main_test
2
-
3
- import (
4
- "github.com/cockroachdb/errors"
5
- "github.com/jarcoal/httpmock"
6
- "github.com/stretchr/testify/assert"
7
- "github.com/sue445/funnel_http"
8
- "io"
9
- "net/http"
10
- "testing"
11
- )
12
-
13
- func TestRunRequests(t *testing.T) {
14
- httpmock.Activate()
15
- t.Cleanup(httpmock.DeactivateAndReset)
16
-
17
- httpmock.RegisterResponder("GET", "http://example.com/1",
18
- func(req *http.Request) (*http.Response, error) {
19
- resp := httpmock.NewStringResponse(200, "GET http://example.com/1")
20
-
21
- resp.Header.Set("Content-Type", "text/plain")
22
-
23
- for key, values := range req.Header {
24
- for _, value := range values {
25
- resp.Header.Add(key, value)
26
- }
27
- }
28
-
29
- return resp, nil
30
- })
31
-
32
- httpmock.RegisterResponder("GET", "http://example.com/2",
33
- func(req *http.Request) (*http.Response, error) {
34
- resp := httpmock.NewStringResponse(200, "GET http://example.com/2")
35
-
36
- resp.Header.Set("Content-Type", "text/plain")
37
-
38
- for key, values := range req.Header {
39
- for _, value := range values {
40
- resp.Header.Add(key, value)
41
- }
42
- }
43
-
44
- return resp, nil
45
- })
46
-
47
- httpmock.RegisterResponder("POST", "http://example.com/1",
48
- func(req *http.Request) (*http.Response, error) {
49
- payload, err := io.ReadAll(req.Body)
50
- if err != nil {
51
- return nil, errors.WithStack(err)
52
- }
53
-
54
- resp := httpmock.NewStringResponse(200, string(payload))
55
-
56
- resp.Header.Set("Content-Type", "text/plain")
57
-
58
- for key, values := range req.Header {
59
- for _, value := range values {
60
- resp.Header.Add(key, value)
61
- }
62
- }
63
-
64
- return resp, nil
65
- })
66
-
67
- tests := []struct {
68
- name string
69
- requests []main.Request
70
- expected []main.Response
71
- }{
72
- {
73
- name: "GET 1 request",
74
- requests: []main.Request{
75
- {
76
- Method: "GET",
77
- URL: "http://example.com/1",
78
- Header: map[string][]string{
79
- "X-My-Request-Header": {"a", "b"},
80
- },
81
- },
82
- },
83
- expected: []main.Response{
84
- {
85
- StatusCode: 200,
86
- Body: []byte("GET http://example.com/1"),
87
- Header: map[string][]string{
88
- "Content-Type": {"text/plain"},
89
- "X-My-Request-Header": {"a", "b"},
90
- },
91
- },
92
- },
93
- },
94
- {
95
- name: "GET multiple requests",
96
- requests: []main.Request{
97
- {
98
- Method: "GET",
99
- URL: "http://example.com/1",
100
- Header: map[string][]string{
101
- "X-My-Request-Header": {"a", "b"},
102
- },
103
- },
104
- {
105
- Method: "GET",
106
- URL: "http://example.com/2",
107
- Header: map[string][]string{
108
- "X-My-Request-Header": {"c", "d"},
109
- },
110
- },
111
- },
112
- expected: []main.Response{
113
- {
114
- StatusCode: 200,
115
- Body: []byte("GET http://example.com/1"),
116
- Header: map[string][]string{
117
- "Content-Type": {"text/plain"},
118
- "X-My-Request-Header": {"a", "b"},
119
- },
120
- },
121
- {
122
- StatusCode: 200,
123
- Body: []byte("GET http://example.com/2"),
124
- Header: map[string][]string{
125
- "Content-Type": {"text/plain"},
126
- "X-My-Request-Header": {"c", "d"},
127
- },
128
- },
129
- },
130
- },
131
- {
132
- name: "POST 1 request",
133
- requests: []main.Request{
134
- {
135
- Method: "POST",
136
- URL: "http://example.com/1",
137
- Header: map[string][]string{
138
- "X-My-Request-Header": {"a", "b"},
139
- },
140
- Body: []byte("111"),
141
- },
142
- },
143
- expected: []main.Response{
144
- {
145
- StatusCode: 200,
146
- Body: []byte("111"),
147
- Header: map[string][]string{
148
- "Content-Type": {"text/plain"},
149
- "X-My-Request-Header": {"a", "b"},
150
- },
151
- },
152
- },
153
- },
154
- {
155
- name: "POST multiple requests",
156
- requests: []main.Request{
157
- {
158
- Method: "POST",
159
- URL: "http://example.com/1",
160
- Header: map[string][]string{
161
- "X-My-Request-Header": {"a", "b"},
162
- },
163
- Body: []byte("111"),
164
- },
165
- {
166
- Method: "POST",
167
- URL: "http://example.com/1",
168
- Header: map[string][]string{
169
- "X-My-Request-Header": {"c", "d"},
170
- },
171
- Body: []byte("222"),
172
- },
173
- },
174
- expected: []main.Response{
175
- {
176
- StatusCode: 200,
177
- Body: []byte("111"),
178
- Header: map[string][]string{
179
- "Content-Type": {"text/plain"},
180
- "X-My-Request-Header": {"a", "b"},
181
- },
182
- },
183
- {
184
- StatusCode: 200,
185
- Body: []byte("222"),
186
- Header: map[string][]string{
187
- "Content-Type": {"text/plain"},
188
- "X-My-Request-Header": {"c", "d"},
189
- },
190
- },
191
- },
192
- },
193
- }
194
-
195
- httpClient := http.Client{}
196
- for _, tt := range tests {
197
- t.Run(tt.name, func(t *testing.T) {
198
- actual, err := main.RunRequests(&httpClient, tt.requests)
199
- if assert.NoError(t, err) {
200
- assert.Equal(t, tt.expected, actual)
201
- }
202
- })
203
- }
204
- }