@@ -7,6 +7,7 @@ import * as Fiber from "effect/Fiber";
77import * as PubSub from "effect/PubSub" ;
88import * as Ref from "effect/Ref" ;
99import * as Stream from "effect/Stream" ;
10+ import * as TestClock from "effect/testing/TestClock" ;
1011
1112import { makeManagedServerProvider } from "./makeManagedServerProvider.ts" ;
1213
@@ -101,45 +102,71 @@ const enrichedSnapshotSecond: ServerProvider = {
101102} ;
102103
103104describe ( "makeManagedServerProvider" , ( ) => {
104- it . effect (
105- "runs the initial provider check in the background and streams the refreshed snapshot" ,
106- ( ) =>
107- Effect . scoped (
108- Effect . gen ( function * ( ) {
109- const checkCalls = yield * Ref . make ( 0 ) ;
110- const releaseCheck = yield * Deferred . make < void > ( ) ;
111- const provider = yield * makeManagedServerProvider < TestSettings > ( {
112- maintenanceCapabilities,
113- getSettings : Effect . succeed ( { enabled : true } ) ,
114- streamSettings : Stream . empty ,
115- haveSettingsChanged : ( previous , next ) => previous . enabled !== next . enabled ,
116- initialSnapshot : ( ) => Effect . succeed ( initialSnapshot ) ,
117- checkProvider : Ref . update ( checkCalls , ( count ) => count + 1 ) . pipe (
118- Effect . flatMap ( ( ) => Deferred . await ( releaseCheck ) ) ,
119- Effect . as ( refreshedSnapshot ) ,
120- ) ,
121- refreshInterval : "1 hour" ,
122- } ) ;
105+ it . effect ( "does not probe during construction or unchanged snapshot reads" , ( ) =>
106+ Effect . scoped (
107+ Effect . gen ( function * ( ) {
108+ const checkCalls = yield * Ref . make ( 0 ) ;
109+ const provider = yield * makeManagedServerProvider < TestSettings > ( {
110+ maintenanceCapabilities,
111+ getSettings : Effect . succeed ( { enabled : true } ) ,
112+ streamSettings : Stream . empty ,
113+ haveSettingsChanged : ( previous , next ) => previous . enabled !== next . enabled ,
114+ initialSnapshot : ( ) => Effect . succeed ( initialSnapshot ) ,
115+ checkProvider : Ref . update ( checkCalls , ( count ) => count + 1 ) . pipe (
116+ Effect . as ( refreshedSnapshot ) ,
117+ ) ,
118+ refreshInterval : "1 hour" ,
119+ } ) ;
123120
124- const initial = yield * provider . getSnapshot ;
125- assert . deepStrictEqual ( initial , initialSnapshot ) ;
121+ yield * Effect . yieldNow ;
126122
127- const updatesFiber = yield * Stream . take ( provider . streamChanges , 1 ) . pipe (
128- Stream . runCollect ,
129- Effect . forkChild ,
130- ) ;
131- yield * Effect . yieldNow ;
123+ assert . deepStrictEqual ( yield * provider . getSnapshot , initialSnapshot ) ;
124+ assert . deepStrictEqual ( yield * provider . getSnapshot , initialSnapshot ) ;
125+ assert . strictEqual ( yield * Ref . get ( checkCalls ) , 0 ) ;
126+ } ) ,
127+ ) ,
128+ ) ;
132129
133- yield * Deferred . succeed ( releaseCheck , undefined ) ;
130+ it . effect ( "streams an explicit provider refresh" , ( ) =>
131+ Effect . scoped (
132+ Effect . gen ( function * ( ) {
133+ const checkCalls = yield * Ref . make ( 0 ) ;
134+ const releaseCheck = yield * Deferred . make < void > ( ) ;
135+ const provider = yield * makeManagedServerProvider < TestSettings > ( {
136+ maintenanceCapabilities,
137+ getSettings : Effect . succeed ( { enabled : true } ) ,
138+ streamSettings : Stream . empty ,
139+ haveSettingsChanged : ( previous , next ) => previous . enabled !== next . enabled ,
140+ initialSnapshot : ( ) => Effect . succeed ( initialSnapshot ) ,
141+ checkProvider : Ref . update ( checkCalls , ( count ) => count + 1 ) . pipe (
142+ Effect . flatMap ( ( ) => Deferred . await ( releaseCheck ) ) ,
143+ Effect . as ( refreshedSnapshot ) ,
144+ ) ,
145+ refreshInterval : "1 hour" ,
146+ } ) ;
147+
148+ const initial = yield * provider . getSnapshot ;
149+ assert . deepStrictEqual ( initial , initialSnapshot ) ;
150+
151+ const updatesFiber = yield * Stream . take ( provider . streamChanges , 1 ) . pipe (
152+ Stream . runCollect ,
153+ Effect . forkChild ,
154+ ) ;
155+ const refreshFiber = yield * provider . refresh . pipe ( Effect . forkChild ) ;
156+ yield * Effect . yieldNow ;
157+
158+ yield * Deferred . succeed ( releaseCheck , undefined ) ;
134159
135- const updates = Array . from ( yield * Fiber . join ( updatesFiber ) ) ;
136- const latest = yield * provider . getSnapshot ;
160+ const refreshed = yield * Fiber . join ( refreshFiber ) ;
161+ const updates = Array . from ( yield * Fiber . join ( updatesFiber ) ) ;
162+ const latest = yield * provider . getSnapshot ;
137163
138- assert . deepStrictEqual ( updates , [ refreshedSnapshot ] ) ;
139- assert . deepStrictEqual ( latest , refreshedSnapshot ) ;
140- assert . strictEqual ( yield * Ref . get ( checkCalls ) , 1 ) ;
141- } ) ,
142- ) ,
164+ assert . deepStrictEqual ( refreshed , refreshedSnapshot ) ;
165+ assert . deepStrictEqual ( updates , [ refreshedSnapshot ] ) ;
166+ assert . deepStrictEqual ( latest , refreshedSnapshot ) ;
167+ assert . strictEqual ( yield * Ref . get ( checkCalls ) , 1 ) ;
168+ } ) ,
169+ ) ,
143170 ) ;
144171
145172 it . effect ( "reruns the provider check when streamed settings change" , ( ) =>
@@ -148,7 +175,6 @@ describe("makeManagedServerProvider", () => {
148175 const settingsRef = yield * Ref . make < TestSettings > ( { enabled : true } ) ;
149176 const settingsChanges = yield * PubSub . unbounded < TestSettings > ( ) ;
150177 const checkCalls = yield * Ref . make ( 0 ) ;
151- const releaseInitialCheck = yield * Deferred . make < void > ( ) ;
152178 const releaseSettingsCheck = yield * Deferred . make < void > ( ) ;
153179 const provider = yield * makeManagedServerProvider < TestSettings > ( {
154180 maintenanceCapabilities,
@@ -157,36 +183,95 @@ describe("makeManagedServerProvider", () => {
157183 haveSettingsChanged : ( previous , next ) => previous . enabled !== next . enabled ,
158184 initialSnapshot : ( ) => Effect . succeed ( initialSnapshot ) ,
159185 checkProvider : Ref . updateAndGet ( checkCalls , ( count ) => count + 1 ) . pipe (
160- Effect . flatMap ( ( count ) =>
161- count === 1
162- ? Deferred . await ( releaseInitialCheck ) . pipe ( Effect . as ( refreshedSnapshot ) )
163- : Deferred . await ( releaseSettingsCheck ) . pipe ( Effect . as ( refreshedSnapshotSecond ) ) ,
186+ Effect . flatMap ( ( ) =>
187+ Deferred . await ( releaseSettingsCheck ) . pipe ( Effect . as ( refreshedSnapshotSecond ) ) ,
164188 ) ,
165189 ) ,
166190 refreshInterval : "1 hour" ,
167191 } ) ;
168192
169- const updatesFiber = yield * Stream . take ( provider . streamChanges , 2 ) . pipe (
193+ const updatesFiber = yield * Stream . take ( provider . streamChanges , 1 ) . pipe (
170194 Stream . runCollect ,
171195 Effect . forkChild ,
172196 ) ;
173197 yield * Effect . yieldNow ;
174198
175- yield * Deferred . succeed ( releaseInitialCheck , undefined ) ;
176199 yield * Ref . set ( settingsRef , { enabled : false } ) ;
177200 yield * PubSub . publish ( settingsChanges , { enabled : false } ) ;
178201 yield * Deferred . succeed ( releaseSettingsCheck , undefined ) ;
179202
180203 const updates = Array . from ( yield * Fiber . join ( updatesFiber ) ) ;
181204 const latest = yield * provider . getSnapshot ;
182205
183- assert . deepStrictEqual ( updates , [ refreshedSnapshot , refreshedSnapshotSecond ] ) ;
206+ assert . deepStrictEqual ( updates , [ refreshedSnapshotSecond ] ) ;
184207 assert . deepStrictEqual ( latest , refreshedSnapshotSecond ) ;
185- assert . strictEqual ( yield * Ref . get ( checkCalls ) , 2 ) ;
208+ assert . strictEqual ( yield * Ref . get ( checkCalls ) , 1 ) ;
186209 } ) ,
187210 ) ,
188211 ) ;
189212
213+ it . effect ( "ignores streamed settings updates that do not change provider settings" , ( ) =>
214+ Effect . scoped (
215+ Effect . gen ( function * ( ) {
216+ const settingsRef = yield * Ref . make < TestSettings > ( { enabled : true } ) ;
217+ const settingsChanges = yield * PubSub . unbounded < TestSettings > ( ) ;
218+ const checkCalls = yield * Ref . make ( 0 ) ;
219+ const provider = yield * makeManagedServerProvider < TestSettings > ( {
220+ maintenanceCapabilities,
221+ getSettings : Ref . get ( settingsRef ) ,
222+ streamSettings : Stream . fromPubSub ( settingsChanges ) ,
223+ haveSettingsChanged : ( previous , next ) => previous . enabled !== next . enabled ,
224+ initialSnapshot : ( ) => Effect . succeed ( initialSnapshot ) ,
225+ checkProvider : Ref . update ( checkCalls , ( count ) => count + 1 ) . pipe (
226+ Effect . as ( refreshedSnapshot ) ,
227+ ) ,
228+ refreshInterval : "1 hour" ,
229+ } ) ;
230+
231+ yield * PubSub . publish ( settingsChanges , { enabled : true } ) ;
232+ yield * Effect . yieldNow ;
233+
234+ assert . deepStrictEqual ( yield * provider . getSnapshot , initialSnapshot ) ;
235+ assert . strictEqual ( yield * Ref . get ( checkCalls ) , 0 ) ;
236+ } ) ,
237+ ) ,
238+ ) ;
239+
240+ it . effect ( "still refreshes on the configured periodic interval" , ( ) =>
241+ Effect . scoped (
242+ Effect . gen ( function * ( ) {
243+ const checkCalls = yield * Ref . make ( 0 ) ;
244+ const provider = yield * makeManagedServerProvider < TestSettings > ( {
245+ maintenanceCapabilities,
246+ getSettings : Effect . succeed ( { enabled : true } ) ,
247+ streamSettings : Stream . empty ,
248+ haveSettingsChanged : ( previous , next ) => previous . enabled !== next . enabled ,
249+ initialSnapshot : ( ) => Effect . succeed ( initialSnapshot ) ,
250+ checkProvider : Ref . updateAndGet ( checkCalls , ( count ) => count + 1 ) . pipe (
251+ Effect . map ( ( count ) => ( {
252+ ...refreshedSnapshot ,
253+ checkedAt : `2026-04-10T00:00:0${ count } .000Z` ,
254+ } ) ) ,
255+ ) ,
256+ refreshInterval : "1 minute" ,
257+ } ) ;
258+
259+ const updatesFiber = yield * Stream . take ( provider . streamChanges , 1 ) . pipe (
260+ Stream . runCollect ,
261+ Effect . forkChild ,
262+ ) ;
263+
264+ yield * TestClock . adjust ( "1 minute" ) ;
265+ yield * Effect . yieldNow ;
266+
267+ const updates = Array . from ( yield * Fiber . join ( updatesFiber ) ) ;
268+ assert . deepStrictEqual ( updates , [ refreshedSnapshot ] ) ;
269+ assert . deepStrictEqual ( yield * provider . getSnapshot , refreshedSnapshot ) ;
270+ assert . strictEqual ( yield * Ref . get ( checkCalls ) , 1 ) ;
271+ } ) ,
272+ ) . pipe ( Effect . provide ( TestClock . layer ( ) ) ) ,
273+ ) ;
274+
190275 it . effect ( "streams supplemental snapshot updates after the base provider check completes" , ( ) =>
191276 Effect . scoped (
192277 Effect . gen ( function * ( ) {
@@ -210,9 +295,11 @@ describe("makeManagedServerProvider", () => {
210295 Stream . runCollect ,
211296 Effect . forkChild ,
212297 ) ;
298+ const refreshFiber = yield * provider . refresh . pipe ( Effect . forkChild ) ;
213299 yield * Effect . yieldNow ;
214300
215301 yield * Deferred . succeed ( releaseCheck , undefined ) ;
302+ yield * Fiber . join ( refreshFiber ) ;
216303
217304 yield * Deferred . succeed ( releaseEnrichment , undefined ) ;
218305
@@ -262,10 +349,12 @@ describe("makeManagedServerProvider", () => {
262349 Stream . runCollect ,
263350 Effect . forkChild ,
264351 ) ;
352+ const firstRefreshFiber = yield * provider . refresh . pipe ( Effect . forkChild ) ;
265353 yield * Effect . yieldNow ;
266354
267355 yield * Deferred . succeed ( allowFirstRefresh , undefined ) ;
268356 yield * Deferred . await ( firstCallbackReady ) ;
357+ yield * Fiber . join ( firstRefreshFiber ) ;
269358
270359 yield * provider . refresh ;
271360 yield * Deferred . await ( secondCallbackReady ) ;
0 commit comments