polyphony 0.34 → 0.41

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.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +11 -2
  3. data/.gitignore +2 -2
  4. data/.rubocop.yml +30 -0
  5. data/CHANGELOG.md +34 -0
  6. data/Gemfile +0 -11
  7. data/Gemfile.lock +11 -10
  8. data/README.md +2 -1
  9. data/Rakefile +6 -2
  10. data/TODO.md +18 -95
  11. data/docs/_includes/head.html +40 -0
  12. data/docs/_includes/nav.html +5 -5
  13. data/docs/api-reference.md +1 -1
  14. data/docs/api-reference/fiber.md +18 -0
  15. data/docs/api-reference/gyro-async.md +57 -0
  16. data/docs/api-reference/gyro-child.md +29 -0
  17. data/docs/api-reference/gyro-queue.md +44 -0
  18. data/docs/api-reference/gyro-timer.md +51 -0
  19. data/docs/api-reference/gyro.md +25 -0
  20. data/docs/index.md +10 -7
  21. data/docs/main-concepts/design-principles.md +67 -9
  22. data/docs/main-concepts/extending.md +1 -1
  23. data/docs/main-concepts/fiber-scheduling.md +55 -72
  24. data/examples/core/xx-agent.rb +102 -0
  25. data/examples/core/xx-fork-cleanup.rb +22 -0
  26. data/examples/core/xx-sleeping.rb +14 -6
  27. data/examples/core/xx-timer-gc.rb +17 -0
  28. data/examples/io/tunnel.rb +48 -0
  29. data/examples/io/xx-irb.rb +1 -1
  30. data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +7 -6
  31. data/examples/performance/thread-vs-fiber/polyphony_server.rb +14 -25
  32. data/ext/{gyro → polyphony}/extconf.rb +2 -2
  33. data/ext/polyphony/fiber.c +112 -0
  34. data/ext/{gyro → polyphony}/libev.c +0 -0
  35. data/ext/{gyro → polyphony}/libev.h +0 -0
  36. data/ext/polyphony/libev_agent.c +503 -0
  37. data/ext/polyphony/libev_queue.c +214 -0
  38. data/ext/polyphony/polyphony.c +89 -0
  39. data/ext/{gyro/gyro.h → polyphony/polyphony.h} +49 -59
  40. data/ext/polyphony/polyphony_ext.c +23 -0
  41. data/ext/{gyro → polyphony}/socket.c +21 -19
  42. data/ext/{gyro → polyphony}/thread.c +55 -119
  43. data/ext/{gyro → polyphony}/tracing.c +1 -1
  44. data/lib/polyphony.rb +37 -44
  45. data/lib/polyphony/adapters/fs.rb +1 -4
  46. data/lib/polyphony/adapters/irb.rb +2 -2
  47. data/lib/polyphony/adapters/postgres.rb +6 -5
  48. data/lib/polyphony/adapters/process.rb +27 -23
  49. data/lib/polyphony/adapters/trace.rb +110 -105
  50. data/lib/polyphony/core/channel.rb +35 -35
  51. data/lib/polyphony/core/exceptions.rb +29 -29
  52. data/lib/polyphony/core/global_api.rb +94 -91
  53. data/lib/polyphony/core/resource_pool.rb +83 -83
  54. data/lib/polyphony/core/sync.rb +16 -16
  55. data/lib/polyphony/core/thread_pool.rb +49 -37
  56. data/lib/polyphony/core/throttler.rb +30 -23
  57. data/lib/polyphony/event.rb +27 -0
  58. data/lib/polyphony/extensions/core.rb +23 -14
  59. data/lib/polyphony/extensions/fiber.rb +269 -267
  60. data/lib/polyphony/extensions/io.rb +56 -26
  61. data/lib/polyphony/extensions/openssl.rb +5 -9
  62. data/lib/polyphony/extensions/socket.rb +29 -10
  63. data/lib/polyphony/extensions/thread.rb +19 -12
  64. data/lib/polyphony/net.rb +64 -60
  65. data/lib/polyphony/version.rb +1 -1
  66. data/polyphony.gemspec +3 -6
  67. data/test/helper.rb +14 -1
  68. data/test/stress.rb +17 -12
  69. data/test/test_agent.rb +77 -0
  70. data/test/{test_async.rb → test_event.rb} +17 -9
  71. data/test/test_ext.rb +25 -4
  72. data/test/test_fiber.rb +23 -14
  73. data/test/test_global_api.rb +5 -5
  74. data/test/test_io.rb +46 -24
  75. data/test/test_queue.rb +74 -0
  76. data/test/test_signal.rb +3 -40
  77. data/test/test_socket.rb +33 -0
  78. data/test/test_thread.rb +38 -16
  79. data/test/test_thread_pool.rb +3 -3
  80. data/test/test_throttler.rb +0 -1
  81. data/test/test_trace.rb +6 -5
  82. metadata +34 -39
  83. data/ext/gyro/async.c +0 -158
  84. data/ext/gyro/child.c +0 -117
  85. data/ext/gyro/gyro.c +0 -203
  86. data/ext/gyro/gyro_ext.c +0 -31
  87. data/ext/gyro/io.c +0 -447
  88. data/ext/gyro/queue.c +0 -142
  89. data/ext/gyro/selector.c +0 -183
  90. data/ext/gyro/signal.c +0 -108
  91. data/ext/gyro/timer.c +0 -154
  92. data/test/test_timer.rb +0 -56
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ea4d90a517ed25294e677a9d3298ee2f4f79ad269e222c2a6e3a786fed605b50
4
- data.tar.gz: 19581d1dea73db08a6b9b0816fd4500c7ca84b2692150585133b7e3f99ee0522
3
+ metadata.gz: ebbaa936b265f2e46ff30cab71b7c85e5ebd31396f7b8ecb8fc01156f6e35f79
4
+ data.tar.gz: 677c90c266a7d677f124f964775d849a350f925c0441f9aa6cba3a4745ff1e5d
5
5
  SHA512:
6
- metadata.gz: 36291ddf1dedbed0fbdcb347811e657bad19661981cacff2fa9736246e883fa2f56fa4362f266721177559e295adefe3f92c1797e4773dfc03b45857d2ebb3fb
7
- data.tar.gz: 8d9a5f0d368167a300e9926c9ad2d57221a423b60dc18d8a395c114feb18e3fa96546ac7709bf8acbabca500ec56d373bcd8f38479183c00077f0ccf513fb039
6
+ metadata.gz: 732f1eaa117ec2483661451b98a43192ec3e757bde24b4f0eb115fee057efd55fa306af2ed484d3fa943b09e2913a76b9b34a4a8f7eed3a64ea06c27c44b3c17
7
+ data.tar.gz: b9a0595dbf7f338c0b1d67f121090261f0a6efb8c1cb342717a5b94b54a346e1eeadee9b62fd916c4cc3ad400d5466119b3a806f4f611b863682eef10b6b2cfe
@@ -4,12 +4,21 @@ on: [push]
4
4
 
5
5
  jobs:
6
6
  build:
7
- runs-on: ubuntu-latest
7
+ strategy:
8
+ fail-fast: false
9
+ matrix:
10
+ os: [ubuntu-latest]
11
+ ruby: [2.6, 2.7]
12
+
13
+ name: >-
14
+ ${{matrix.os}}, ${{matrix.ruby}}
15
+
16
+ runs-on: ${{matrix.os}}
8
17
  steps:
9
18
  - uses: actions/checkout@v1
10
19
  - uses: actions/setup-ruby@v1
11
20
  with:
12
- ruby-version: 2.6.5
21
+ ruby-version: ${{matrix.ruby}}
13
22
  - name: Install dependencies
14
23
  run: |
15
24
  gem install bundler
data/.gitignore CHANGED
@@ -52,8 +52,8 @@ build-iPhoneSimulator/
52
52
  test.rb
53
53
  .vscode
54
54
 
55
- lib/gyro_ext.bundle
56
- lib/gyro_ext.so
55
+ lib/*.bundle
56
+ lib/*.so
57
57
 
58
58
  _site
59
59
  .sass-cache
@@ -143,3 +143,33 @@ Style/HashTransformKeys:
143
143
 
144
144
  Style/HashTransformValues:
145
145
  Enabled: true
146
+
147
+ Layout/EmptyLinesAroundAttributeAccessor:
148
+ Enabled: true
149
+
150
+ Layout/SpaceAroundMethodCallOperator:
151
+ Enabled: true
152
+
153
+ Lint/DeprecatedOpenSSLConstant:
154
+ Enabled: true
155
+
156
+ Lint/MixedRegexpCaptureTypes:
157
+ Enabled: true
158
+
159
+ Lint/RaiseException:
160
+ Enabled: true
161
+
162
+ Lint/StructNewOverride:
163
+ Enabled: true
164
+
165
+ Style/ExponentialNotation:
166
+ Enabled: true
167
+
168
+ Style/RedundantRegexpCharacterClass:
169
+ Enabled: true
170
+
171
+ Style/RedundantRegexpEscape:
172
+ Enabled: true
173
+
174
+ Style/SlicingWithRange:
175
+ Enabled: true
@@ -1,5 +1,39 @@
1
+ ## 0.41 2020-06-27
2
+
3
+ * Introduce System Agent design, remove all `Gyro` classes
4
+
5
+ ## 0.40 2020-05-04
6
+
7
+ * More improvements to stability after fork
8
+
9
+ ## 0.38 2020-04-13
10
+
11
+ * Fix post-fork segfault if parent process has multiple threads with active watchers
12
+
13
+ ## 0.37 2020-04-07
14
+
15
+ * Explicitly kill threads on exit to prevent possible segfault
16
+ * Remove Modulation dependency
17
+
18
+ ## 0.36 2020-03-31
19
+
20
+ * More docs
21
+ * More C code refactoring
22
+ * Fix freeing for active child, signal watchers
23
+
24
+ ## 0.35 2020-03-29
25
+
26
+ * Rename `Fiber#cancel!` to `Fiber#cancel`
27
+ * Rename `Gyro::Async#signal!` to `Gyro::Async#signal`
28
+ * Use `Fiber#auto_watcher` in thread pool, thread extension
29
+ * Implement `Fiber#auto_io` for reusing IO watcher instances
30
+ * Refactor C code
31
+
1
32
  ## 0.34 2020-03-25
2
33
 
34
+ * Add `Fiber#auto_watcher` mainly for use in places like `Gyro::Queue#shift`
35
+ * Refactor C extension
36
+ * Improved GC'ing for watchers
3
37
  * Implement process supervisor (`Polyphony::ProcessSupervisor`)
4
38
  * Improve fiber supervision
5
39
  * Fix forking behaviour
data/Gemfile CHANGED
@@ -1,14 +1,3 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
-
5
- # gem "jekyll", "~> 3.8.6"
6
- # gem "jekyll-remote-theme"
7
- # gem "jekyll-seo-tag"
8
- # gem "just-the-docs"
9
-
10
- # # gem "github-pages", group: :jekyll_plugins
11
-
12
- # group :jekyll_plugins do
13
- # gem "jekyll-feed", "~> 0.6"
14
- # end
@@ -1,8 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.34)
5
- modulation (~> 1.0)
4
+ polyphony (0.41)
6
5
 
7
6
  GEM
8
7
  remote: https://rubygems.org/
@@ -28,7 +27,6 @@ GEM
28
27
  multi_xml (>= 0.5.2)
29
28
  i18n (0.9.5)
30
29
  concurrent-ruby (~> 1.0)
31
- jaro_winkler (1.5.4)
32
30
  jekyll (3.8.6)
33
31
  addressable (~> 2.4)
34
32
  colorator (~> 1.0)
@@ -73,14 +71,13 @@ GEM
73
71
  builder
74
72
  minitest (>= 5.0)
75
73
  ruby-progressbar
76
- modulation (1.0)
77
74
  multi_xml (0.6.0)
78
75
  parallel (1.19.1)
79
76
  parser (2.7.0.2)
80
77
  ast (~> 2.4.0)
81
78
  pathutil (0.16.2)
82
79
  forwardable-extended (~> 2.6)
83
- pg (1.1.3)
80
+ pg (1.1.4)
84
81
  public_suffix (4.0.3)
85
82
  rainbow (3.0.0)
86
83
  rake (12.3.3)
@@ -90,16 +87,20 @@ GEM
90
87
  rb-inotify (0.10.1)
91
88
  ffi (~> 1.0)
92
89
  redis (4.1.0)
90
+ regexp_parser (1.7.1)
93
91
  rexml (3.2.4)
94
92
  rouge (3.15.0)
95
- rubocop (0.80.0)
96
- jaro_winkler (~> 1.5.1)
93
+ rubocop (0.85.1)
97
94
  parallel (~> 1.10)
98
95
  parser (>= 2.7.0.1)
99
96
  rainbow (>= 2.2.2, < 4.0)
97
+ regexp_parser (>= 1.7)
100
98
  rexml
99
+ rubocop-ast (>= 0.0.3)
101
100
  ruby-progressbar (~> 1.7)
102
- unicode-display_width (>= 1.4.0, < 1.7)
101
+ unicode-display_width (>= 1.4.0, < 2.0)
102
+ rubocop-ast (0.0.3)
103
+ parser (>= 2.7.0.1)
103
104
  ruby-progressbar (1.10.1)
104
105
  rubyzip (2.0.0)
105
106
  safe_yaml (1.0.5)
@@ -129,11 +130,11 @@ DEPENDENCIES
129
130
  localhost (= 1.1.4)
130
131
  minitest (= 5.13.0)
131
132
  minitest-reporters (= 1.4.2)
132
- pg (= 1.1.3)
133
+ pg (= 1.1.4)
133
134
  polyphony!
134
135
  rake-compiler (= 1.0.5)
135
136
  redis (= 4.1.0)
136
- rubocop (= 0.80.0)
137
+ rubocop (= 0.85.1)
137
138
  simplecov (= 0.17.1)
138
139
 
139
140
  BUNDLED WITH
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  # Polyphony - Fine-Grained Concurrency for Ruby
2
2
 
3
+
3
4
  [![Gem Version](https://badge.fury.io/rb/polyphony.svg)](http://rubygems.org/gems/polyphony)
4
5
  [![Modulation Test](https://github.com/digital-fabric/polyphony/workflows/Tests/badge.svg)](https://github.com/digital-fabric/polyphony/actions?query=workflow%3ATests)
5
6
  [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/digital-fabric/polyphony/blob/master/LICENSE)
@@ -46,4 +47,4 @@ The complete documentation for Polyphony could be found on the
46
47
 
47
48
  Issues and pull requests will be gladly accepted. Please use the [Polyphony git
48
49
  repository](https://github.com/digital-fabric/polyphony) as your primary point
49
- of departure for contributing.
50
+ of departure for contributing.
data/Rakefile CHANGED
@@ -4,8 +4,8 @@ require "bundler/gem_tasks"
4
4
  require "rake/clean"
5
5
 
6
6
  require "rake/extensiontask"
7
- Rake::ExtensionTask.new("gyro_ext") do |ext|
8
- ext.ext_dir = "ext/gyro"
7
+ Rake::ExtensionTask.new("polyphony_ext") do |ext|
8
+ ext.ext_dir = "ext/polyphony"
9
9
  end
10
10
 
11
11
  task :recompile => [:clean, :compile]
@@ -15,6 +15,10 @@ task :test do
15
15
  exec 'ruby test/run.rb'
16
16
  end
17
17
 
18
+ task :stress_test do
19
+ exec 'ruby test/stress.rb'
20
+ end
21
+
18
22
  task :docs do
19
23
  exec 'RUBYOPT=-W0 jekyll serve -s docs'
20
24
  end
data/TODO.md CHANGED
@@ -1,38 +1,8 @@
1
- - Would it be possible to spin up a fiber on another thread?
2
-
3
- The use case is being able to supervise fibers that run on separate threads.
4
- This might be useful for distributing jobs (such as handling HTTP connections)
5
- over multiple threads.
1
+ ## 0.42 Update docs
6
2
 
7
- For this we need:
3
+ -
8
4
 
9
- - A way to communicate to a thread that it needs to spin up a fiber, the
10
- simplest solution is to start a fiber accepting spin requests for each
11
- thread (in `Thread#initialize`).
12
- - An API:
13
-
14
- ```ruby
15
- spin(on_thread: thread) { do_something_important }
16
- ```
17
-
18
- An alternative is to turn the main fiber of spawned threads into a child of
19
- the spawning fiber. But since a lot of people might start threads without any
20
- regard to fibers, it might be better to implement this in a new API. An
21
- example of the top of my head for threads that shouldn't be children of the
22
- spawning fiber is our own test helper, which kills all child fibers after each
23
- test. MiniTest has some threads it spawns for running tests in parallel, and
24
- we don't want to stop them after each test!
25
-
26
- So, a good solution would be:
27
-
28
- ```ruby
29
- t = Thread.new { do_stuff }
30
- t.parent_fiber = Fiber.current
31
- # or otherwise:
32
- Fiber.current.add_child_fiber(t.main_fiber)
33
- ```
34
-
35
- ## 0.35 Some more API work, more docs
5
+ ## 0.43 Some more API work, more docs
36
6
 
37
7
  - Debugging
38
8
  - Eat your own dogfood: need a good tool to check what's going on when some
@@ -142,17 +112,11 @@
142
112
  - Docs
143
113
  - landing page:
144
114
  - links to the interesting stuff
145
- - concurrency overview
146
- - faq
147
115
  - benchmarks
148
116
  - explain difference between `sleep` and `suspend`
149
- - add explanation about async vs sync
150
117
  - discuss using `snooze` for ensuring responsiveness when executing CPU-bound work
151
118
 
152
- - Check why first call to `#sleep` returns too early in tests. Check the
153
- sleep behaviour in a spawned thread.
154
-
155
- ## 0.36 Sinatra / Sidekiq
119
+ ## 0.44 Sinatra / Sidekiq
156
120
 
157
121
  - sintra app with database access (postgresql)
158
122
 
@@ -162,13 +126,11 @@
162
126
  - test performance
163
127
  - proceed from there
164
128
 
165
- ## 0.37 Testing && Docs
129
+ ## 0.45 Testing && Docs
166
130
 
167
131
  - Pull out redis/postgres code, put into new `polyphony-xxx` gems
168
132
 
169
- ## 0.38 Integration
170
-
171
- ## 0.39 Real IO#gets and IO#read
133
+ ## 0.46 Real IO#gets and IO#read
172
134
 
173
135
  - More tests
174
136
  - Implement some basic stuff missing:
@@ -178,11 +140,11 @@
178
140
  - `IO.foreach`
179
141
  - `Process.waitpid`
180
142
 
181
- ## 0.40 Rails
143
+ ## 0.47 Rails
182
144
 
183
145
  - Rails?
184
146
 
185
- ## 0.41 DNS
147
+ ## 0.48 DNS
186
148
 
187
149
  ### DNS client
188
150
 
@@ -215,56 +177,17 @@ Prior art:
215
177
 
216
178
  - https://github.com/socketry/async-dns
217
179
 
218
- ### Work on API
219
-
220
- - Introduce mailbox limiting:
221
- - add API for limiting mailbox size:
222
-
223
- ```ruby
224
- Fiber.current.mailbox_limit = 1000
225
- ```
226
-
227
- - Add the limit for `Gyro::Queue`
228
-
229
- ```ruby
230
- Gyro::Queue.new(1000)
231
- ```
232
-
233
- - Pushing to a limited queue will block if limit is reached
234
-
235
- - Introduce selective receive:
236
-
237
- ```ruby
238
- # returns (or waits for) the first message for which the block returns true
239
- (_, item) = receive { |msg| msg.first == ref }
240
- ```
241
-
242
- Possible implementation:
243
-
244
- ```ruby
245
- def receive
246
- return @mailbox.shift unless block_given?
247
-
248
- loop
249
- msg = @mailbox.shift
250
- return msg if yield(msg)
251
-
252
- # message didn't match condition, put it back in queue
253
- @mailbox.push msg
254
- end
255
- end
256
- ```
180
+ ## Work on API
257
181
 
258
182
  - Add option for setting the exception raised on cancelling using `#cancel_after`:
259
183
 
260
- ```ruby
261
- cancel_after(3, with_error: MyErrorClass) do
262
- do_my_thing
263
- end
264
-
265
- # or a RuntimeError with message
266
- cancel_after(3, with_error: 'Cancelling due to timeout') do
267
- do_my_thing
268
- end
269
- ```
184
+ ```ruby
185
+ cancel_after(3, with_error: MyErrorClass) do
186
+ do_my_thing
187
+ end
188
+ # or a RuntimeError with message
189
+ cancel_after(3, with_error: 'Cancelled due to timeout') do
190
+ do_my_thing
191
+ end
192
+ ```
270
193
 
@@ -0,0 +1,40 @@
1
+ <head>
2
+ <meta charset="UTF-8">
3
+ <meta http-equiv="X-UA-Compatible" content="IE=Edge">
4
+
5
+ {% if site.plugins.jekyll-seo == nil %}
6
+ <title>{{ page.title }} - {{ site.title }}</title>
7
+
8
+ {% if page.description %}
9
+ <meta name="Description" content="{{ page.description }}">
10
+ {% endif %}
11
+ {% endif %}
12
+
13
+ <link rel="shortcut icon" href="{{ '/favicon.ico' | relative_url }}" type="image/x-icon">
14
+
15
+ <link rel="stylesheet" href="{{ '/assets/css/just-the-docs.css' | relative_url }}">
16
+
17
+ {% if site.ga_tracking != nil %}
18
+ <script async src="https://www.googletagmanager.com/gtag/js?id={{ site.ga_tracking }}"></script>
19
+ <script>
20
+ window.dataLayer = window.dataLayer || [];
21
+ function gtag(){dataLayer.push(arguments);}
22
+ gtag('js', new Date());
23
+
24
+ gtag('config', "{{ site.ga_tracking }}");
25
+ </script>
26
+
27
+ {% endif %}
28
+
29
+ {% if site.search_enabled != false %}
30
+ <script type="text/javascript" src="{{ '/assets/js/vendor/lunr.min.js' | relative_url }}"></script>
31
+ {% endif %}
32
+ <script type="text/javascript" src="{{ '/assets/js/just-the-docs.js' | relative_url }}"></script>
33
+
34
+ <meta name="viewport" content="width=device-width, initial-scale=1">
35
+
36
+ {% seo %}
37
+
38
+ {% include head_custom.html %}
39
+
40
+ </head>
@@ -9,12 +9,12 @@
9
9
  {% if node.section %}section-title{% endif %}
10
10
  ">
11
11
  {%- if page.parent == node.title or page.grand_parent == node.title -%}
12
- {%- assign first_level_url = node.section_link | node.url | absolute_url -%}
12
+ {%- assign first_level_url = node.section_link | node.url | relative_url -%}
13
13
  {%- endif -%}
14
14
  {%- if node.section -%}
15
15
  <span class="section-title">{{ node.title }}</span>
16
16
  {%- else -%}
17
- <a href="{{ node.url | absolute_url }}" class="navigation-list-link{% if page.url == node.url %} active{% endif %}">{{ node.title }}</a>
17
+ <a href="{{ node.url | relative_url }}" class="navigation-list-link{% if page.url == node.url %} active{% endif %}">{{ node.title }}</a>
18
18
  {%- endif -%}
19
19
  {%- if node.has_children -%}
20
20
  {%- if node.alphabetical_order -%}
@@ -26,15 +26,15 @@
26
26
  {%- for child in children_list -%}
27
27
  <li class="navigation-list-item {% if page.url == child.url or page.parent == child.title %} active{% endif %}">
28
28
  {%- if page.url == child.url or page.parent == child.title -%}
29
- {%- assign second_level_url = child.url | absolute_url -%}
29
+ {%- assign second_level_url = child.url | relative_url -%}
30
30
  {%- endif -%}
31
- <a href="{{ child.url | absolute_url }}" class="navigation-list-link{% if page.url == child.url %} active{% endif %}">{{ child.title }}</a>
31
+ <a href="{{ child.url | relative_url }}" class="navigation-list-link{% if page.url == child.url %} active{% endif %}">{{ child.title }}</a>
32
32
  {%- if child.has_children -%}
33
33
  {%- assign grand_children_list = site.html_pages | where: "parent", child.title | sort:"nav_order" -%}
34
34
  <ul class="navigation-list-child-list">
35
35
  {%- for grand_child in grand_children_list -%}
36
36
  <li class="navigation-list-item {% if page.url == grand_child.url %} active{% endif %}">
37
- <a href="{{ grand_child.url | absolute_url }}" class="navigation-list-link{% if page.url == grand_child.url %} active{% endif %}">{{ grand_child.title }}</a>
37
+ <a href="{{ grand_child.url | relative_url }}" class="navigation-list-link{% if page.url == grand_child.url %} active{% endif %}">{{ grand_child.title }}</a>
38
38
  </li>
39
39
  {%- endfor -%}
40
40
  </ul>