polyphony 0.34 → 0.41

Sign up to get free protection for your applications and to get access to all the features.
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>