Comments (12)
An issue that looked for the (almost, time-based though) same thing: #83
from reactiveswift.
Can you give a little more detail about what you're trying to do?
from reactiveswift.
The idea is basically to create a state machine, where an action will restart from the last point it failed:
let step1: SignalProducer<A, AnyError>
let step2: (A) -> SignalProducer<B, AnyError>
let step3: (B) -> SignalProducer<C, AnyError>
let task = step1
.replaySuccessLazily() // don't love this name
.flatMap(.concat, transform: step2)
.replaySuccessLazily()
.flatMap(.concat, transform: step3)
.replaySuccessLazily()
let action = Action { _ in task }
from reactiveswift.
It seems the prominent need here is a mean to "fail gracefully" by invalidating the cached values and restarting the producer. Composing withretry(upTo:)
can do the later but not the former.
It is like how #83 asked for a producer that invalidates the cached image upon a timeout event, and restarts the wrapped producer.
I'd say we may introduce a specialized replayLazily
overload for something like Error == ReplayCacheInvalidation
. #83 would be made possible by using timeout
, and for this issue a mapError
or flatMapError
to ReplayCacheInvalidation
.
from reactiveswift.
It seems like you should move the retries into the steps.
let step1: SignalProducer<A, AnyError>
let step2: (A) -> SignalProducer<B, AnyError>
let step3: (B) -> SignalProducer<C, AnyError>
let task = step1
.retry(upTo: 3)
.flatMap(.concat) { step2($0).retry(upTo: 3) }
.flatMap(.concat) { step3($0).retry(upTo: 3) }
let action = Action { _ in task }
Would that work?
from reactiveswift.
I don't think retry()
does what I want here, because it retries the producer automatically. What I'm after is a way to have a producer replay values and completion on start, but if the multicasted producer has failed then the cached events should be discarded and it should be like starting the producer for the first time.
from reactiveswift.
In my snippet above, step3
will be retried automatically—without restarting steps 1 or 2—if it fails, reusing the value from step 2. It sounded like that was what you wanted.
But if you really want to replay all values, then you'd need a custom operator like that. I can't think of a better name for it, so I'd probably add it like that to your project until/unless a it solidifies into something more clear.
from reactiveswift.
I'll be honest, I'm a little daunted by the complexity of replayLazily
, and the idea of largely duplicating that in a new operator (or multiple!).
I've been doing some thinking about introducing the notion of a caching policy, and I'd like to spitball a possible approach here. I think it would be possible to extend replayLazily
to take an optional parameter policy
:
// current behaviour, and the default value
replayLazily(upTo: Int.max, policy: .alwaysReplay)
// behaviour described in this issue
replayLazily(upTo: Int.max, policy: .replayCompleted)
// behaviour described in #83
replayLazily(upTo: Int.max, policy: .timeout(after: .seconds(1), on: QueueScheduler()))
The policy would be defined something like this:
enum ReplayAction {
case replay
case invalidate
}
/// A function that allows responding to any event by invalidating the cache asynchronously
struct ReplayCachePolicy<Value, Error: Swift.Error> {
let action: (_ event: Event<Value, Error>) -> SignalProducer<ReplayAction, NoError>
}
extension ReplayCachePolicy {
static var alwaysReplay: ReplayCachePolicy {
return .init { _ in
SignalProducer(value: .replay)
}
}
static func timeout(after interval: DispatchTimeInterval, on scheduler: DateScheduler) -> ReplayCachePolicy {
return .init { event in
guard event.isTerminating else {
return SignalProducer(value: .replay)
}
return SignalProducer(value: .invalidate)
.delay(interval, on: scheduler)
}
}
static var replayCompleted: ReplayCachePolicy {
return .init { event in
switch event {
case .value, .completed:
return SignalProducer(value: .replay)
case .failed .interrupted:
return SignalProducer(value: .invalidate)
}
}
}
}
Then, when starting the multicasted, replayed producer, observe the cache policy events something like this:
multicastedSignal
.materialize()
.flatMap(.merge) { policy.action($0).take(first: 1) }
.filter { $0 == .invalidate }
.take(first: 1)
.observeValues { _ in
// ensure replay state is reset, so that next time the producer is started, the underlying producer will be restarted instead of replayed
}
What do you think? Would something like this be an appropriate change? Does it belong in a separate operator? Is it not worth the additional complexity?
from reactiveswift.
As I might have mentioned, a separated operator might not be necessary. Since for both your case and #83 the requirement is replaying invalidation & restarting on failure, we may provide a overload that acts differently with a specific instance of error.
// current behaviour, and the default value
producer.replayLazily(upTo: Int.max)
// behaviour described in this issue
producer
.mapError { _ in ReplayCacheInvalidation() }
.replayLazily(upTo: Int.max)
// behaviour described in #83
// (The producer is not of `NoError` error type.)
producer
.mapError { _ in ReplayCacheInvalidation() }
.timeout(10.0, raising: ReplayCacheInvalidation(), on: UIScheduler())
.replayLazily(upTo: Int.max)
For this overload, upon receiving failure
, it purges the cached values - so that new observers do not see the old values - and restarts the producer.
Edit: Expanded a bit on the code snippet for #83.
from reactiveswift.
I've been doing some thinking about introducing the notion of a caching policy, and I'd like to spitball a possible approach here. I think it would be possible to extend replayLazily to take an optional parameter policy:
That seems sensible to me. 👍
from reactiveswift.
@andersio What is ReplayCacheInvalidation
and how does it invalidate the cache on failures?
from reactiveswift.
Hello. 👋 Thanks for opening this issue. Due to inactivity, we will soft close the issue. If you feel that it should remain open, please let us know. 😄
from reactiveswift.
Related Issues (20)
- Release 6.6.0 requires Swift 5.3 and therefore Xcode 12.x
- Using "<~" binding function with Signal.Observers causes memory leaks. HOT 3
- Using old xcconfig causing problems with Carthage & Apple Silicon macOS builds
- Support await / AsyncSequence HOT 13
- Playground does not work HOT 1
- Hello, ask a question about Disposable, thanks HOT 1
- What's means 'targeting' in QueueScheduler? HOT 2
- Signal.merge reported issue after migrating from ReactiveSwift from 4.0.0 -> 6.6.0 HOT 2
- xCode13 CompileSwiftSources normal x86_64 com.apple.xcode.tools.swift.compiler
- Usage with SwiftUI HOT 4
- Could not find module 'ReactiveSwift' for target 'arm64-apple-ios-simulator' HOT 2
- [BUG] XCode 14 beta 3 - bitcode issue HOT 1
- Is it planned to add count argument to `collect(every:on:skipEmpty:discardWhenCompleted:)`?
- Adopt OSAllocatedUnfairLock on iOS 16 HOT 9
- Add support for mapping Property/MutableProperty types to a Binding
- Signal triggered by phone call when device is closed HOT 3
- Infinite recursion in observeSwitchToLatest() HOT 3
- EXC_BAD_ACCESS Crashes occur in xcode15 HOT 4
- Reactive Swift crash with getCache function and observeSwitchToLatest signal
- Is there any plan for future releases? HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from reactiveswift.