featurehub-sdk 2.0.1 → 2.1.0

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: bc48d48647d7b4aee1a53a733506382f3e6cb021de19ae9c7192a38ff3af38a9
4
- data.tar.gz: 499b54873a2cbb87e72dcb815509a8260f12ec0ffa6a4b529ac779acad7c4729
3
+ metadata.gz: e641291e7daf8a2bb0209ecfd7b0af27fc46b4cd17645bbe7072171ee0c8eb79
4
+ data.tar.gz: c37349075e7d5ccdff4776d6980f612e0e8b3bd9d5964124aab104dcf06a991a
5
5
  SHA512:
6
- metadata.gz: 1f3620cf2da86a7a897efae7c766b00eaf98549c9c9b90dee97f14c67c9d32718cdf4046accfdd887622b80bb44943704fda18acfa179ed90b801c9938bd2130
7
- data.tar.gz: f31beae7e13e8261b541ffc211a3a8dad8c49563918d12e178f9390b4d079bcd303d8273f5741986bc1907d12d7e646bf0f62c553527ed87ee83ca77834c1f42
6
+ metadata.gz: efe9d777183431e8729c37aba09384998c82d8b52eddf2835e47aba7ea60546630a09587fe6f8639c1f4daddb637c68b915daf4dbcdd362ba59b8960ca68d321
7
+ data.tar.gz: c028d22c9f8e32077a69e2e0bbc2ba34ea96892cfd78431f480ea020bdf9d7baec15c3af8bb3c0cbe0497c112eec372cd5615f9393fbd5b9dc73a7bcbb08f7fc
data/.claude/CLAUDE.md CHANGED
@@ -83,3 +83,4 @@ Type definitions live in [sig/feature_hub/featurehub.rbs](sig/feature_hub/featur
83
83
  - RuboCop: max line length 120, metrics cops disabled, documentation disabled
84
84
  - Tests mirror lib structure: `spec/feature_hub/sdk/**/*_spec.rb`
85
85
  - Use `instance_double` for mocking, `aggregate_failures` for multiple assertions
86
+ - after making changes run `bundle exec rubocop -a` to autocorrect minor offences and understand what major offences may have been introduced and fix them
data/.dockerignore ADDED
@@ -0,0 +1,12 @@
1
+ /bin
2
+ /sig
3
+ /spec
4
+ /.rpsec
5
+ /.rubocop.yml
6
+ /*.md
7
+ /.github
8
+ /examples/rails-example
9
+ /examples/sinatra/logs
10
+ /.git
11
+ /.idea
12
+ /.claude
data/.rubocop.yml CHANGED
@@ -35,8 +35,6 @@ Metrics/CyclomaticComplexity:
35
35
  Naming/FileName:
36
36
  Enabled: false
37
37
 
38
- Gemspec/DeprecatedAttributeAssignment:
39
- Enabled: true
40
38
  Gemspec/DeprecatedAttributeAssignment: # new in 1.30
41
39
  Enabled: true
42
40
  Gemspec/RequireMFA: # new in 1.23
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## [2.1.0] - 2026-04-14
2
+
3
+ - Once the Config is closed it won't reopen
4
+ - Added Memcache cache that operates on the same general principles as Redis.
5
+ It requires Dalli to be available in your dependencies at least 4.x.
6
+ - The requirement for faraday 2+ has been relaxed, just faraday is now required in
7
+ the gemspec. It has been tested with 2 and 1.
8
+ - Redis session store has been updated so it only uses two keys
9
+
1
10
  ## [2.0.1] - 2026-03-27
2
11
 
3
12
  - Remove `FeatureHub::Sdk.default_logger`; logger now defaults to `nil` instead of a stdout DEBUG logger
data/Gemfile CHANGED
@@ -15,7 +15,7 @@ gem "simplecov", "~> 0.21"
15
15
 
16
16
  gem "concurrent-ruby", "~> 1.3"
17
17
 
18
- gem "faraday", "~> 2"
18
+ gem "faraday"
19
19
 
20
20
  gem "murmurhash3", "~> 0.1.7"
21
21
 
data/Gemfile.lock CHANGED
@@ -1,9 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- featurehub-sdk (2.0.1)
4
+ featurehub-sdk (2.1.0)
5
5
  concurrent-ruby (~> 1.3)
6
- faraday (~> 2)
6
+ faraday
7
7
  ld-eventsource (~> 2.5.1)
8
8
  murmurhash3 (~> 0.1.7)
9
9
  sem_version (~> 2.0.0)
@@ -16,6 +16,8 @@ GEM
16
16
  ast (2.4.3)
17
17
  concurrent-ruby (1.3.6)
18
18
  connection_pool (3.0.2)
19
+ dalli (4.3.3)
20
+ logger
19
21
  diff-lcs (1.6.2)
20
22
  docile (1.4.1)
21
23
  domain_name (0.6.20240107)
@@ -113,7 +115,8 @@ PLATFORMS
113
115
 
114
116
  DEPENDENCIES
115
117
  concurrent-ruby (~> 1.3)
116
- faraday (~> 2)
118
+ dalli (~> 4)
119
+ faraday
117
120
  featurehub-sdk!
118
121
  ld-eventsource (~> 2.5.1)
119
122
  murmurhash3 (~> 0.1.7)
@@ -129,12 +132,13 @@ CHECKSUMS
129
132
  ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
130
133
  concurrent-ruby (1.3.6) sha256=6b56837e1e7e5292f9864f34b69c5a2cbc75c0cf5338f1ce9903d10fa762d5ab
131
134
  connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a
135
+ dalli (4.3.3) sha256=ae58aa3442b0d9e129898f56bc6e3a0f8b6149523e723b3eb124a05ae9a2da0c
132
136
  diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962
133
137
  docile (1.4.1) sha256=96159be799bfa73cdb721b840e9802126e4e03dfc26863db73647204c727f21e
134
138
  domain_name (0.6.20240107) sha256=5f693b2215708476517479bf2b3802e49068ad82167bcd2286f899536a17d933
135
139
  faraday (2.14.0) sha256=8699cfe5d97e55268f2596f9a9d5a43736808a943714e3d9a53e6110593941cd
136
140
  faraday-net_http (3.4.2) sha256=f147758260d3526939bf57ecf911682f94926a3666502e24c69992765875906c
137
- featurehub-sdk (2.0.1)
141
+ featurehub-sdk (2.1.0)
138
142
  ffi (1.17.3-arm64-darwin) sha256=0c690555d4cee17a7f07c04d59df39b2fba74ec440b19da1f685c6579bb0717f
139
143
  ffi (1.17.3-x86_64-darwin) sha256=1f211811eb5cfaa25998322cdd92ab104bfbd26d1c4c08471599c511f2c00bb5
140
144
  ffi (1.17.3-x86_64-linux-gnu) sha256=3746b01f677aae7b16dc1acb7cb3cc17b3e35bdae7676a3f568153fb0e2c887f
data/Makefile ADDED
@@ -0,0 +1,12 @@
1
+ e2e:
2
+ docker build -t todo-server:e2e --progress=plain -f examples/sinatra/Dockerfile .
3
+
4
+ run-e2e: e2e
5
+
6
+ cop:
7
+ bundle exec rubocop -a
8
+
9
+ spec:
10
+ bundle exec rspec
11
+
12
+ ci: cop spec
data/README.md CHANGED
@@ -295,34 +295,87 @@ The file path defaults to `featurehub-overrides.yaml` or the `FEATUREHUB_LOCAL_Y
295
295
 
296
296
  ## Caching feature state in Redis
297
297
 
298
- `RedisSessionStore` persists feature values from a `FeatureHubRepository` to Redis. On startup it replays cached features into the repository, then listens for live updates and writes newer versions back. A background timer re-reads all features periodically so updates from other processes are picked up automatically.
298
+ `RedisSessionStore` persists feature values from a `FeatureHubRepository` to Redis. On startup it replays cached features into the repository, then listens for live updates and writes newer versions back. A background timer periodically re-reads a SHA key so that updates published by other processes are picked up automatically.
299
299
 
300
300
  > **Warning:** Do not use `RedisSessionStore` with server-evaluated features. Each server-evaluated context resolves to different values; sharing a single Redis key across processes will cause them to overwrite each other's state.
301
301
 
302
+ Multi-process writes are safe: the store uses SHA256-based change detection and Redis `WATCH`/`MULTI`/`EXEC` to atomically update both keys and prevent races between concurrent writers.
303
+
304
+ Pass a `FeatureHubConfig` as the second argument — the store reads `repository` and `environment_id` from it and registers itself as a raw update listener automatically.
305
+
302
306
  ```ruby
303
307
  # Requires the 'redis' gem: gem 'redis', '~> 5'
304
308
  store = FeatureHub::Sdk::RedisSessionStore.new(
305
309
  "redis://localhost:6379",
306
- config.repository,
310
+ config, # FeatureHubConfig — NOT config.repository
307
311
  {
308
- prefix: "myapp", # Redis key prefix (default: "featurehub")
309
- namespace: 0, # Redis DB index (default: 0)
310
- timeout: 60, # Seconds between periodic reloads (default: 30)
311
- password: "secret", # Optional Redis password
312
- logger: my_logger # Optional logger (default: SDK default logger)
312
+ prefix: "myapp", # Redis key prefix (default: "featurehub")
313
+ db: 0, # Redis DB index (default: 0)
314
+ refresh_timeout: 300, # Seconds between periodic SHA checks (default: 300)
315
+ backoff_timeout: 500, # Milliseconds to wait between WATCH retries (default: 500)
316
+ retry_update_count: 10, # Maximum WATCH retry attempts per write (default: 10)
317
+ logger: my_logger # Optional logger
313
318
  }
314
319
  )
315
320
 
316
- # Register it so it also receives live updates
317
- config.register_raw_update_listener(store)
318
-
319
321
  # Shut down cleanly
320
322
  store.close
321
323
  ```
322
324
 
325
+ You can also pass an existing Redis client instead of a connection string (e.g. a RedisCluster client or a pre-configured `Redis` instance):
326
+
327
+ ```ruby
328
+ redis = Redis.new(url: "redis://localhost:6379", db: 1)
329
+ store = FeatureHub::Sdk::RedisSessionStore.new(redis, config)
330
+ ```
331
+
332
+ You can also pass a `RedisSessionStoreOptions` object directly:
333
+
334
+ ```ruby
335
+ opts = FeatureHub::Sdk::RedisSessionStoreOptions.new(prefix: "myapp", db: 2)
336
+ store = FeatureHub::Sdk::RedisSessionStore.new("redis://localhost:6379", config, opts)
337
+ ```
338
+
323
339
  Redis keys used:
324
- - `{prefix}_ids` — a Redis SET of feature IDs
325
- - `{prefix}_{id}` — the JSON-encoded feature state for each feature
340
+ - `{prefix}_{environment_id}` — JSON-encoded array of all feature states
341
+ - `{prefix}_{environment_id}_sha` — SHA256 fingerprint used for cross-process change detection
342
+
343
+ ## Caching feature state in Memcache
344
+
345
+ `MemcacheSessionStore` persists feature values from a `FeatureHubRepository` to Memcache. On startup it reads any previously saved features from Memcache and replays them into the repository, then listens for live updates and writes newer versions back. A background timer periodically re-reads a SHA key so that updates published by other processes are picked up automatically.
346
+
347
+ > **Warning:** Do not use `MemcacheSessionStore` with server-evaluated features. Each server-evaluated context resolves to different values; sharing a single Memcache key across processes will cause them to overwrite each other's state.
348
+
349
+ Multi-process writes are safe: the store uses SHA256-based change detection and Dalli's compare-and-set (`cas`) to prevent races between concurrent writers.
350
+
351
+ ```ruby
352
+ # Requires the 'dalli' gem: gem 'dalli', '~> 5'
353
+ store = FeatureHub::Sdk::MemcacheSessionStore.new(
354
+ "localhost:11211",
355
+ config,
356
+ {
357
+ prefix: "myapp", # Key prefix (default: "featurehub")
358
+ refresh_timeout: 300, # Seconds between periodic SHA checks (default: 300)
359
+ backoff_timeout: 500, # Milliseconds to wait between CAS retries (default: 500)
360
+ retry_update_count: 10, # Maximum CAS retry attempts per write (default: 10)
361
+ logger: my_logger # Optional logger (default: SDK default logger)
362
+ }
363
+ )
364
+
365
+ # Shut down cleanly
366
+ store.close
367
+ ```
368
+
369
+ You can also pass an existing `Dalli::Client` instead of a connection string:
370
+
371
+ ```ruby
372
+ dalli = Dalli::Client.new("localhost:11211", serializer: JSON)
373
+ store = FeatureHub::Sdk::MemcacheSessionStore.new(dalli, config)
374
+ ```
375
+
376
+ Memcache keys used:
377
+ - `{prefix}_{environment_id}` — JSON-encoded array of all feature states
378
+ - `{prefix}_{environment_id}_sha` — SHA256 fingerprint used for cross-process change detection
326
379
 
327
380
  ## Custom raw update listeners
328
381
 
@@ -346,7 +399,7 @@ end
346
399
  config.register_raw_update_listener(MyAuditListener.new)
347
400
  ```
348
401
 
349
- Callbacks are dispatched asynchronously via `Concurrent::Future`. The `source` parameter will be `"streaming"`, `"polling"`, `"local-yaml"`, `"redis-store"`, or `"unknown"`.
402
+ Callbacks are dispatched asynchronously via `Concurrent::Future`. The `source` parameter will be `"streaming"`, `"polling"`, `"local-yaml"`, `"redis-store"`, `"memcache-store"`, or `"unknown"`.
350
403
 
351
404
  All listeners are closed automatically when `config.close` or `repository.close` is called.
352
405
 
@@ -1,31 +1,31 @@
1
- FROM ruby:3.3.10-bookworm
1
+ FROM phusion/passenger-ruby33:latest
2
2
 
3
3
  MAINTAINER info@featurehub.io
4
- ENV BUNDLER_VERSION 2.3.15
4
+ ENV BUNDLER_VERSION 4.0.3
5
5
  ARG DEBIAN_FRONTEND=noninteractive
6
6
 
7
- RUN apt update && \
8
- apt install -y gnupg wget tzdata apt-transport-https dirmngr gnupg curl && \
9
- curl https://oss-binaries.phusionpassenger.com/auto-software-signing-gpg-key-2025.txt | gpg --dearmor | tee /etc/apt/trusted.gpg.d/phusion.gpg >/dev/null && \
10
- sh -c 'echo deb https://oss-binaries.phusionpassenger.com/apt/passenger bookworm main > /etc/apt/sources.list.d/passenger.list' && \
11
- apt-get update && \
12
- apt-get install -y nginx passenger
13
-
14
- #ENV BUNDLE_PATH /bundle
15
- RUN passenger-config build-native-support
7
+ # The purpose of this Dockerfile is to build a test to-do server that can be used against the
8
+ # e2e tests. It *MUST* test the SDK on the current HEAD, so the file is complicated and awkward
9
+ # and not like a typical deploy.
16
10
 
17
11
  RUN echo 'gem: --no-document' >> ~/.gemrc && \
18
12
  gem update --system && \
19
13
  gem install bundler -v ${BUNDLER_VERSION} --force
20
14
 
15
+ RUN gem uninstall logger -v 1.6.0
16
+
21
17
  # set up nsswitch
22
18
  COPY examples/sinatra/conf/nsswitch.conf /etc/nsswitch.conf
23
19
 
24
- RUN mkdir -p /app/featurehub
25
20
  COPY examples/sinatra/conf/nginx.conf /etc/nginx/nginx.conf
26
- COPY . /app/
21
+ ADD . /app/featurehub
27
22
  WORKDIR /app/featurehub
28
- RUN cd /app/featurehub && bundle install
29
- ADD examples/sinatra/ /app/featurehub
23
+ RUN rm Gemfile Gemfile.lock && cd examples/sinatra && bundle config set --local deployment 'true' --without 'development test' path 'vendor/bundle'
24
+ RUN cd /app/featurehub/examples/sinatra && cat .bundle/config && mkdir logs
25
+ RUN cd /app/featurehub/examples/sinatra && bundle install
26
+ RUN chown -R nobody /app
27
+ ENV BUNDLE_PATH=/app/featurehub/examples/sinatra/vendor/bundle
30
28
 
31
- CMD /usr/sbin/nginx -g \'daemon off;\'
29
+ USER root
30
+ CMD /usr/sbin/nginx -g 'daemon off;'
31
+ #CMD /usr/bin/bash
@@ -4,7 +4,11 @@ source "https://rubygems.org"
4
4
 
5
5
  ruby "3.3.10"
6
6
 
7
+ # 5 prevents us using ruby 3.2 which while EOL is still in our build
8
+ gem "dalli", "~> 4"
7
9
  gem "featurehub-sdk", path: "../.."
10
+ # this is just to test 1.x works OK
11
+ gem "faraday", "~> 1"
8
12
  gem "rack"
9
13
  gem "redis"
10
14
  gem "sinatra"
@@ -1,9 +1,9 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- featurehub-sdk (2.0.0)
4
+ featurehub-sdk (2.1.0)
5
5
  concurrent-ruby (~> 1.3)
6
- faraday (~> 2)
6
+ faraday
7
7
  ld-eventsource (~> 2.5.1)
8
8
  murmurhash3 (~> 0.1.7)
9
9
  sem_version (~> 2.0.0)
@@ -16,15 +16,35 @@ GEM
16
16
  concurrent-ruby (1.3.6)
17
17
  connection_pool (3.0.2)
18
18
  daemons (1.4.1)
19
+ dalli (4.3.3)
20
+ logger
19
21
  domain_name (0.6.20240107)
20
22
  eventmachine (1.2.7)
21
- faraday (2.14.1)
22
- faraday-net_http (>= 2.0, < 3.5)
23
- json
24
- logger
25
- faraday-net_http (3.4.2)
26
- net-http (~> 0.5)
23
+ faraday (1.10.5)
24
+ faraday-em_http (~> 1.0)
25
+ faraday-em_synchrony (~> 1.0)
26
+ faraday-excon (~> 1.1)
27
+ faraday-httpclient (~> 1.0)
28
+ faraday-multipart (~> 1.0)
29
+ faraday-net_http (~> 1.0)
30
+ faraday-net_http_persistent (~> 1.0)
31
+ faraday-patron (~> 1.0)
32
+ faraday-rack (~> 1.0)
33
+ faraday-retry (~> 1.0)
34
+ ruby2_keywords (>= 0.0.4)
35
+ faraday-em_http (1.0.0)
36
+ faraday-em_synchrony (1.0.1)
37
+ faraday-excon (1.1.0)
38
+ faraday-httpclient (1.0.1)
39
+ faraday-multipart (1.2.0)
40
+ multipart-post (~> 2.0)
41
+ faraday-net_http (1.0.2)
42
+ faraday-net_http_persistent (1.2.0)
43
+ faraday-patron (1.0.0)
44
+ faraday-rack (1.0.0)
45
+ faraday-retry (1.0.4)
27
46
  ffi (1.17.3-x86_64-darwin)
47
+ ffi (1.17.3-x86_64-linux-gnu)
28
48
  ffi-compiler (1.3.2)
29
49
  ffi (>= 1.15.5)
30
50
  rake
@@ -36,7 +56,6 @@ GEM
36
56
  http-cookie (1.1.0)
37
57
  domain_name (~> 0.5)
38
58
  http-form_data (2.3.0)
39
- json (2.19.2)
40
59
  ld-eventsource (2.5.1)
41
60
  concurrent-ruby (~> 1.0)
42
61
  http (>= 4.4.1, < 6.0.0)
@@ -44,11 +63,10 @@ GEM
44
63
  ffi-compiler (~> 1.0)
45
64
  rake (~> 13.0)
46
65
  logger (1.7.0)
66
+ multipart-post (2.4.1)
47
67
  murmurhash3 (0.1.7)
48
68
  mustermann (2.0.2)
49
69
  ruby2_keywords (~> 0.0.1)
50
- net-http (0.9.1)
51
- uri (>= 0.11.1)
52
70
  public_suffix (7.0.5)
53
71
  rack (2.2.6.4)
54
72
  rack-protection (2.2.3)
@@ -72,7 +90,6 @@ GEM
72
90
  eventmachine (~> 1.0, >= 1.0.4)
73
91
  rack (>= 1, < 3)
74
92
  tilt (2.1.0)
75
- uri (1.1.1)
76
93
 
77
94
  PLATFORMS
78
95
  x86_64-darwin-21
@@ -80,6 +97,8 @@ PLATFORMS
80
97
  x86_64-linux
81
98
 
82
99
  DEPENDENCIES
100
+ dalli (~> 4)
101
+ faraday (~> 1)
83
102
  featurehub-sdk!
84
103
  rack
85
104
  redis
@@ -4,7 +4,23 @@ This is a simple todo server example that we use to run our Cucumber tests again
4
4
  to ensure that the SDK is operating as expected. Please read the `application.rb`
5
5
  for details on how it works, it is fairly simple.
6
6
 
7
- It can be built into a Passenger dockerfile using the `build.sh` script and started
8
- using `docker_start.sh`
7
+ NOTE: The `Dockerfile` is intended for use in the e2e tests in the pipeline and is not a general use-case sample. It uses Passenger, Sinatra and the FeatureHub SDK on this specific branch. It is, as such, constructed from the root directory (using the `Makefile`).
9
8
 
9
+ We typically want to run one cache and then two copies of the server. We would normally disconnect the primary server (running on 8099) from edge, leaving the second server running (8100) and writing to the cache.
10
10
 
11
+ To disconnect from edge, call `curl localhost:8099/health/disconnect`
12
+
13
+ The tests should still pass as the primary server is picking up changes from the cache.
14
+
15
+ == Redis
16
+
17
+ ----
18
+ docker run -d -p 6379:6379 --name redis redis
19
+
20
+ ----
21
+
22
+ == Memcache
23
+
24
+ ----
25
+ docker run -p 11211:11211 --name memcache -d memcached
26
+ ----
@@ -5,14 +5,21 @@ require "sinatra"
5
5
  require "featurehub-sdk"
6
6
  require "json"
7
7
 
8
- def configure_featurehub
8
+ def configure_featurehub(logger)
9
9
  puts "FeatureHub SDK Version is #{FeatureHub::Sdk::VERSION}"
10
10
 
11
- config = FeatureHub::Sdk::FeatureHubConfig.new
11
+ config = FeatureHub::Sdk::FeatureHubConfig.new(nil, nil, nil, nil, logger)
12
12
  repo = config.repository
13
13
 
14
14
  if ENV["FEATUREHUB_REDIS_STORE"]
15
- config.register_raw_update_listener(FeatureHub::Sdk::RedisSessionStore.new(ENV["FEATUREHUB_REDIS_STORE"], repo))
15
+ FeatureHub::Sdk::RedisSessionStore.new(ENV["FEATUREHUB_REDIS_STORE"], config,
16
+ { logger: logger, refresh_timeout: 3 })
17
+ end
18
+
19
+ if ENV["FEATUREHUB_MEMCACHE_STORE"]
20
+ FeatureHub::Sdk::MemcacheSessionStore.new(ENV["FEATUREHUB_MEMCACHE_STORE"],
21
+ config, { logger: logger,
22
+ refresh_timeout: 3 })
16
23
  end
17
24
 
18
25
  if ENV["FEATUREHUB_LOCAL_YAML"]
@@ -20,6 +27,7 @@ def configure_featurehub
20
27
  config.register_interceptor(FeatureHub::Sdk::LocalYamlValueInterceptor.new(watch: true))
21
28
  end
22
29
 
30
+ puts "connecting to FeatureHub"
23
31
  # connect to edge service
24
32
  config.init
25
33
  end
@@ -34,7 +42,9 @@ class App < Sinatra::Base
34
42
  rack = File.new("logs/rack.log", "a+")
35
43
  use Rack::CommonLogger, rack
36
44
 
37
- set :fh_config, configure_featurehub
45
+ logger = Logger.new($stdout)
46
+ set :logger, logger
47
+ set :fh_config, configure_featurehub(logger)
38
48
  set :users, {}
39
49
  end
40
50
 
@@ -42,10 +52,6 @@ class App < Sinatra::Base
42
52
  content_type "application/json"
43
53
  end
44
54
 
45
- get("/config/disconnect-edge") do
46
- settings.fh_config.close_edge
47
- end
48
-
49
55
  # Routes
50
56
  # "resolve" a specific todo for this user
51
57
  put("/todo/:user/:id/resolve") do
@@ -83,6 +89,7 @@ class App < Sinatra::Base
83
89
  if new_todo["title"].nil?
84
90
  status(400)
85
91
  else
92
+ settings.logger.debug("todo is #{new_todo}")
86
93
  todos.push(Todo.new(new_todo["id"] || 1, new_todo["title"], new_todo["resolved"] || false))
87
94
  todo_list(user)
88
95
  end
@@ -94,13 +101,26 @@ class App < Sinatra::Base
94
101
  end
95
102
 
96
103
  get("/health/readiness") do
97
- if config.repository.ready?
104
+ if settings.fh_config.repository.ready?
105
+ "ok"
106
+ else
107
+ status(500)
108
+ end
109
+ end
110
+
111
+ get("/health/liveness") do
112
+ if settings.fh_config.repository.ready?
98
113
  "ok"
99
114
  else
100
115
  status(500)
101
116
  end
102
117
  end
103
118
 
119
+ get("/health/disconnect") do
120
+ settings.fh_config.close_edge
121
+ status 200
122
+ end
123
+
104
124
  private
105
125
 
106
126
  def todo_list(user)
@@ -113,6 +133,7 @@ class App < Sinatra::Base
113
133
  new_todos.push(Todo.new(todo.id, process_title(ctx, todo.title), todo.resolved).to_h)
114
134
  end
115
135
 
136
+ settings.logger.debug("todos #{new_todos}")
116
137
  new_todos.to_json
117
138
  end
118
139
 
@@ -139,15 +160,6 @@ class App < Sinatra::Base
139
160
 
140
161
  new_title = new_title.upcase if ctx.enabled?("FEATURE_TITLE_TO_UPPERCASE")
141
162
 
142
- # puts("features via repository: #{settings.fh_config.repository.features}")
143
- # puts("features via edge service: #{settings.fh_config.get_or_create_edge_service.repository}")
144
-
145
- # puts("enabled? #{ctx.repo.features}")
146
- puts(ctx.enabled?("FEATURE_TITLE_TO_UPPERCASE"))
147
- puts(ctx.flag("FEATURE_TITLE_TO_UPPERCASE"))
148
- puts(settings.fh_config.repository.feature("FEATURE_TITLE_TO_UPPERCASE").feature_type)
149
- puts(settings.fh_config.repository.feature("FEATURE_TITLE_TO_UPPERCASE").flag)
150
-
151
- new_title&.strip
163
+ new_title
152
164
  end
153
165
  end
@@ -11,15 +11,6 @@ events {
11
11
  http {
12
12
 
13
13
 
14
- passenger_user_switching on;
15
- passenger_user root;
16
- passenger_default_user root;
17
-
18
- passenger_max_pool_size 6;
19
-
20
- passenger_disable_security_update_check on;
21
- passenger_disable_anonymous_telemetry on;
22
-
23
14
  include /etc/nginx/conf/vhosts/*.conf;
24
15
  include /etc/nginx/conf.d/*.conf;
25
16
 
@@ -33,8 +24,9 @@ http {
33
24
  access_log /dev/stdout;
34
25
  listen 8099 default_server;
35
26
  server_name localhost;
36
- root /app/featurehub;
37
- passenger_app_root /app/featurehub;
27
+ root /app/featurehub/examples/sinatra;
28
+ passenger_app_root /app/featurehub/examples/sinatra;
29
+ passenger_preload_bundler on;
38
30
  passenger_enabled on;
39
31
  passenger_startup_file config.ru;
40
32
  passenger_app_type rack;
@@ -0,0 +1,16 @@
1
+ server {
2
+ listen 80;
3
+ server_name localhost;
4
+ root /app/featurehub/examples/sinatra;
5
+
6
+ passenger_enabled on;
7
+ passenger_user root;
8
+
9
+ # If this is a Ruby app, specify a Ruby version:
10
+ # For Ruby 3.3
11
+ passenger_ruby /usr/bin/ruby3.3;
12
+
13
+ # Nginx has a default limit of 1 MB for request bodies, which also applies
14
+ # to file uploads. The following line enables uploads of up to 50 MB:
15
+ #client_max_body_size 50M;
16
+ }
@@ -1,6 +1,6 @@
1
1
  services:
2
2
  party-server:
3
- image: featurehub/party-server:1.9.4
3
+ image: featurehub/party-server:latest
4
4
  ports:
5
5
  - 8085:8085
6
6
  user: 999:999
@@ -12,13 +12,41 @@ services:
12
12
  image: redis:latest
13
13
  ports:
14
14
  - 6379:6379
15
- ruby-sinatra:
16
- image: ruby-sinatra:latest
15
+ memcache:
16
+ image: memcached:1.6-alpine
17
+ ports:
18
+ - 11211:11211
19
+ sinatra:
20
+ image: todo-server:e2e
21
+ ports:
22
+ - 8099:8099
23
+ environment:
24
+ RAILS_ENV: production
25
+ FEATUREHUB_CLIENT_API_KEY: "a1286d73-a23b-4f5b-8fdf-04dd03668fb9/xPlhDYnWlKjjZ3maUPquhOUOmk50gn*Hh8Q5qY6JEURrxtEEjzk"
26
+ FEATUREHUB_EDGE_URL: http://party-server:8085
27
+ FEATUREHUB_BASE_URL: http://party-server:8085
28
+ sinatra-redis:
29
+ image: todo-server:e2e
30
+ ports:
31
+ - 8099:8099
32
+ environment:
33
+ FEATUREHUB_POLLING_INTERVAL: "3"
34
+ FEATUREHUB_CLIENT_API_KEY: "a1286d73-a23b-4f5b-8fdf-04dd03668fb9/xPlhDYnWlKjjZ3maUPquhOUOmk50gn*Hh8Q5qY6JEURrxtEEjzk"
35
+ FEATUREHUB_EDGE_URL: http://party-server:8085
36
+ FEATUREHUB_BASE_URL: http://party-server:8085
37
+ FEATUREHUB_REDIS_STORE: redis://redis:6379
38
+ sinatra-memcache:
39
+ image: todo-server:e2e
17
40
  ports:
18
41
  - 8099:8099
19
42
  environment:
43
+ RAILS_ENV: production
44
+ FEATUREHUB_POLLING_INTERVAL: "3"
45
+ FEATUREHUB_CLIENT_API_KEY: "a1286d73-a23b-4f5b-8fdf-04dd03668fb9/xPlhDYnWlKjjZ3maUPquhOUOmk50gn*Hh8Q5qY6JEURrxtEEjzk"
20
46
  FEATUREHUB_EDGE_URL: http://party-server:8085
21
47
  FEATUREHUB_BASE_URL: http://party-server:8085
22
- FEATUREHUB_REDIS_STORE: redis
48
+ FEATUREHUB_MEMCACHE_STORE: memcache
49
+ depends_on:
50
+ - memcache
23
51
  volumes:
24
52
  featurehub-h2-data: