Поток петлевого события, вызывающий состояние гонки - PullRequest
0 голосов
/ 18 мая 2019

Моя общая цель - следить за изменениями в моей базе данных и автоматически передавать эти изменения любому пользователю, подключенному к моему веб-сайту. Проблема, с которой я сталкиваюсь, заключается в том, что у меня есть действие, инициирующее отправку запроса в мою базу данных, и одновременно запускается поток событий, потому что модель, которую я наблюдаю, изменилась. В результате чего выполняется начальное действие, а действие, инициируемое потоком событий, прерывается до его выполнения.

это первое действие, которое запускается для создания новой записи в блоге в моей базе данных

export const topicSubmit = (date, newTopic, newTopicBody, memberId, name) => {
    return {
        type: 'TOPIC_SUBMIT',
        payload: axios({
            method: 'post',
            url: `/api/blogPosts`,
            data: {
                "blogTitle": newTopic,
                "blogBody": newTopicBody,
                "date": date,
                "upVotes": 0,
                "numComments": 0,
                "voteNames": [],
                "memberId": memberId,
                "steamNameId": name
            }
        })
            .then(response => {
                return response.data
            })
            .catch(err => err)
    }
}

// this is the boot script that creates the change stream

var es = require('event-stream');
module.exports = function (app) {
    console.log('realtime boot script')
    var BlogPost = app.models.BlogPost;
    BlogPost.createChangeStream(function (err, changes) {
        changes.pipe(es.stringify()).pipe(process.stdout);
    });
}

// this is the event listener on my front end that will dispatch all
// changes made in my database to my front end

componentDidMount() {
        const { dispatch } = this.props;
          let urlToChangeStream = '/api/blogPosts/change-stream?_format=event-stream';
          let src = new EventSource(urlToChangeStream);
          src.addEventListener('data', function (msg) {
              let data = JSON.parse(msg.data);
          dispatch(liveChangeBlogs(data))
          });

Я ожидаю, что действие 'TOPIC_SUBMIT' должно вернуть выполненное до того, как слушатель события отправит действие 'liveChangeBlogs' Вот документация, которую я нашел в потоке петлевых событий https://loopback.io/doc/en/lb3/Realtime-server-sent-events.html

Ответы [ 2 ]

0 голосов
/ 01 июня 2019

Я решил эту проблему, используя Redux Thunk, добавив setTimeout и закрытие для моего componentDidMount.Действие topicSubmit и загрузочный скрипт не изменились.Не уверен, что setTimeout - правильный путь, но это был единственный способ обойти дело гонки.

 componentDidMount() {
        const { dispatch } = this.props;
        const newBlog = this.handleNewBlog;
        let urlToChangeStream = '/api/blogPosts/change-stream?_format=event-stream';
        let src = new EventSource(urlToChangeStream);
        src.addEventListener('data', function (msg) {
            newBlog(msg)
        });

        const newThread = this.handleNewThread;
        let urlToChangeStream2 = '/api/threads/change-stream?_format=event-stream';
        let src2 = new EventSource(urlToChangeStream2);
        src2.addEventListener('data', function (msg) {
            newThread(msg)
        });
        dispatch(getBlogs());
    }

  handleNewBlog(msg) {
        const { dispatch } = this.props;
        let data = JSON.parse(msg.data);
        if(data.data == undefined) {
            setTimeout(() => {
                dispatch(getBlogs());
            }, 1000);
        } else {
            setTimeout(() => {
                dispatch(liveChangeBlogs(data));
            }, 1000);
        }
    }

 handleNewThread(msg) {
        const { dispatch, viewingThreadId } = this.props;
        let data2 = JSON.parse(msg.data);
        console.log('data2: ', data2)
        if (data2.type == 'remove') {
            return dispatch(getThreadsById(viewingThreadId))
        }
        let id = data2.data.blogPostId
        setTimeout(() => {
            if (viewingThreadId === id) {
                dispatch(getThreadsById(id));
            } else {
                return
            }
        }, 1000);
    }
0 голосов
/ 31 мая 2019

Я ожидаю, что действие 'TOPIC_SUBMIT' должно вернуть выполненное до того, как слушатель события отправит действие 'liveChangeBlogs'

Боюсь, это невозможно. Даже если сервер LoopBack удерживал отправку записи потока событий до тех пор, пока не был отправлен ответ на запрос POST, он все равно не сможет гарантировать, что клиент получит (и обработает!) Ответ на запрос POST перед этим. обрабатывает запись потока событий.

Моя рекомендация состоит в том, чтобы отслеживать запросы в полете на вашем клиенте и отбрасывать записи потока событий для изменений, сделанных тем же клиентом.

Что-то вроде следующего:

const pendingRequests = [];

export const topicSubmit = (date, newTopic, newTopicBody, memberId, name) => {
    const data = {
                "blogTitle": newTopic,
                "blogBody": newTopicBody,
                "date": date,
                "upVotes": 0,
                "numComments": 0,
                "voteNames": [],
                "memberId": memberId,
                "steamNameId": name
            };
    const entry = {type: 'CREATE', data}
    pendingRequests.push(entry);

    return {
        type: 'TOPIC_SUBMIT',
        payload: axios({
            method: 'post',
            url: `/api/blogPosts`,
            data,

        })
            .then(response => {
                return response.data
            })
            .catch(err => err)
            .finally(() => {
              // remove the entry from pending requests
              const ix = pendingRequests.indexOf(entry);
              if (ix > -1) pendingRequests.splice(ix, 1);
            })
    }
}

// this is the event listener on my front end that will dispatch all
// changes made in my database to my front end
// (...)
          src.addEventListener('data', function (msg) {
              let data = JSON.parse(msg.data);
              const ours = pendingRequests.find(it => {
                it.type === data.type && /* check fields that uniquely identify model instance and/or the change being made */
              });
              if (ours) {
                // this event was triggered by us, discard it
                return; 
              }
          dispatch(liveChangeBlogs(data))
          });
...