Skip to content

Resolve fetchNext promise when no data returned - #822

Open
philip-khaisman wants to merge 1 commit into
opensensorhub:mcs_baselinefrom
philip-khaisman:start-replay-when-datasource-is-empty
Open

Resolve fetchNext promise when no data returned#822
philip-khaisman wants to merge 1 commit into
opensensorhub:mcs_baselinefrom
philip-khaisman:start-replay-when-datasource-is-empty

Conversation

@philip-khaisman

@philip-khaisman philip-khaisman commented Jul 30, 2026

Copy link
Copy Markdown

NOTE: This will be merged in botts/osh-js not here. Just wanted eyes outside of botts to see it and provide feedback if necessary

I found an issue where if a data source has no data and i try to replay it with other non-empty data sources (with a data synchronizer) no data streams. Maybe im wrong but that doesn't seem like desired behavior. Ive worked with sensors where one of the datastreams is empty for one reason or another.

This happens because in the DataSynchronizerAlgoReplay class we gate the streaming of data with this check:

if ((nbFetch + nbSkip) === totalDataSources) { start processing data }

nbFetch increments for every data source that has a status of FETCH_STARTED. The empty data source does not have this status. The status is set in the DelegateReplayHandler class in the startLoop() method:

let data = await this.context.nextBatch();
this.context.onChangeStatus(Status.FETCH_STARTED);

Previously nextBatch() (defined in the SweApiReplayContext class) was implemented like this:

    async nextBatch(properties, masterTimestamp, status = {cancel:false}) {
        let version = this.properties.version;
        return new Promise(async (resolve, reject) => {
            try {
                let data;
                let results = [];

                const moveTimeCursor = async () => {...}

                const fetchNext = async () => {
                    data = await this.collection.nextPage();
                    if (status.cancel) {
                        reject('Status has been cancelled');
                    }
                    if (data.length > 0) {
                        results = data;
                        for(let d of results) {
                            d.version = version;
                        }
                        if (status.cancel) {
                            reject('Status has been cancelled');
                        } else {
                            // start startTime cursor
                            this.relativeStartTimestamp = results[results.length-1].timestamp;
                            resolve(data);
                        }
                    }
                }

                await moveTimeCursor();
                await fetchNext();
            } catch (ex) {
                reject(ex);
            }
        });
    }

Note that the condition where data.length === 0) leaves this promise hanging resulting in the FETCH_STARTED status never being set. By resolving the promise to an empty array this promise allows the logic in the startLoop() method to continue, setting the FETCH_STARTED status allowing the replay algorithm to process data. I also added an early return in the startLoop() method since subsequent logic is unnecessary if there is no data returned.

Testing:

  • Load data with data sources that have data and at least one that does not
  • I used the webtak plugin to test
    • Toggle to replay mode
    • Start playback
    • Verify data is visualized

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant