-
-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Resubscribing sends empty value #48
Comments
Hello @nietsuu , Which is probably why you're getting an You can check the parsing error yourself. <script>
import { source } from 'sveltekit-sse';
function subscribe() {
const sse = source('/events')
.select('message')
.json(function or({ error, previous, raw }) {
console.error({ error, raw });
return previous;
});
sse.subscribe((value) => {
console.log(value);
});
}
subscribe(); // Prints correct value
subscribe(); // Still prints correct value
subscribe(); // As long as its called consecutively, it prints the correct value
// HOWEVER when it's called after some time
// even if it's just 100 ms
setTimeout(() => {
subscribe(); // Prints `undefined` SOMETIMES
// I call source() 3 times (different eventName) on my actual code
// 2 of them is undefined, and 1 is correct
// And it's also inconsistent.
// Sometimes, the other one is correct, sometimes it's the other
// What I'm basically saying is that it's random.
// Sometimes even all of them 3 are undefined
}, 100);
</script> The reason for this behavior is because the There is currently no way to do this in svelte <script>
import { source } from 'sveltekit-sse';
const value = source('/events').select('message').json()
</script>
{#await value then result}
{$result}
{/await} without changing the signature of the readable store created by You can create your own promise resolver <script context="module">
/**
* @typedef MyType
* @property {string} data
*/
</script>
<script>
import { onMount } from 'svelte';
import { source } from 'sveltekit-sse';
/** @type {Promise<import('svelte/store').Readable<MyType>>} */
const promise = new Promise(function start(resolve) {
const store = source('/events').select('message').json();
const unsubscribe = store.subscribe(function watch(storeValue) {
if (storeValue) {
unsubscribe();
resolve(store);
}
});
});
onMount(function start() {
/** @type {false|import('svelte/store').Unsubscriber} */
let unsubscribe = false;
promise.then(function run(channel) {
unsubscribe = channel.subscribe(function watch(value) {
console.log(value);
});
});
return function stop() {
if (unsubscribe) {
unsubscribe();
}
};
});
</script> Then you won't get the undefined. I'm sure there's a better way to do that using a derived store. That's a headache though, you're probably better of managing your default values using source::select::json. Other than that, I can't do much going on snippets of code when it comes to specific issues like these that include timing things out. If you can reproduce the error as you see it, I'll take another look. I'll leave this open for now. |
Hello @razshare! Thanks for the response. I understand its asynchronous nature. My problem is different than that. I know for a fact that the store has already a value, but it still returns My initial message was lacking so I understand the misunderstanding. I'm gonna try to provide as much information now here. My code basically looked like this: subscribe();
subscribe();
setTimeout(() => {
subscribe();
}, 1000); Okay here's an interesting part. |
Hello @nietsuu , From what I'm experiencing everything works as intended. And using Without a proper reproduction I cannot help you from the looks of it. |
Hello @razshare! Here's the reproduction repository: https://github.com/nietsuu/test-sveltekit-sse While I was reproducing it, I found out that the problem starts happening if I produceSSE(["event0", "event1"]); // undefined problem occurs
produceSSE(["event0"]); // Works fine |
Hello @nietsuu First of all, update to version 0.13.1 to get the latest fixes described below. I ran your reproduction and I think I figured it out. I'll try to explain myself First let's start from your producer on the server Note that you're emitting once per event name. Remember, connections are cached by default, meaning if you source your data AFTER that emit went off, then you're not going to get anything from the stream. Let's omit the setTimeout for now, and go with this code You'll get this output which is expected - first the undefined, then the server data comes and and we get the actual json value. Now let's introduce the setTimeout You'll get an extra undefined. Which is also correct, because your stream has stopped emitting data as of 1 second ago. Your backend producer is still locked, but it's not sending anything anymore at this point, so the readable gives your the initial default value: undefined. Note See note at the bottom regarding this. Your issue can be solved in two ways - one of which was bugged as of 10 minutes, I just fixed it. 1. The oldest trick in the book - add a query stringIt doesn't matter what query string, any will do, as long as its unique in your domain. 2. The proper way - disabling cachingThis was bugged, I just fixed it. I'm sending you a PR on your reproduction with the query string solution. Let me know if this addresses your issue. Note There is something to be said about that initial undefined. |
Hello @razshare, I think I understand it now. So it actually caches just the connection. It doesn't cache the emitted value itself. That's why I get the Also, I thought all sources of the same In my opinion, I think sources with the same In my actual codebase, I am not actually resubscribing using Making the sources share a store would fix this problem. Ways I know to fix my problemYour solution: Disable cachingThis works. But this also means re-executing the producer which might not be ideal on some cases. Like in my case, my producer is actually connecting to a WebSocket. I wouldn't want to keep reconnecting to the WebSocket every time I navigate to my page. Subscribe at the root route so that it will only do it onceThis works as well. But in my case, I can't do this because it wouldn't make sense to do so in my case. Implement my own store as a wrapper to preserve the emitted valuesFor now, this solution is the best in my case. Let me know if you know a better solution. |
Also, I still don't know why this happens (caching enabled): Case 1 produceSSE(["event0", "event1"]); // undefined problem occurs Case 2 produceSSE(["event0"]); // Not undefined, but emits the last value emitted evidently from the timestamp Case 3 produceSSE(["event1", "event0"]); // Same as Case 2 |
Yeah this makes sense. It should be easy to implement, but I can't do it right now, I'll do it in the evening and I'll let you know when it's ready. |
I'll take a look into these cases too |
Great! Thank you. |
This should make it so that when you subscribe to an already open stream, you obtain the last value of the stream as the first produced value in your subscription. For more details see #48
@razshare |
I'm not really sure how things should work, but whenever I resubscribe after some time:
The text was updated successfully, but these errors were encountered: