2017-10-13 99 views
5

Wpadłem na dziwny problem, szukając najlepszego rozwiązania, które mogę tu uzyskać. Zajmuję się tworzeniem aplikacji szyny, która wyświetla dane ze wspólnej bazy danych, która jest używana przez inną aplikację (nodejs). Wszystkie operacje CRUD odbywają się na drugiej platformie. W aplikacji railsowej po prostu wysyłamy zapytania i wyświetlamy dane.jest jakiś sposób na poznanie aktualizacji bazy danych bez zapytań/mniej zapytań?

W aplikacji szyny muszę automatycznie aktualizować widoki bez odświeżania. na przykład

def index 
    @states = State.page(params[:state_page]) 
    @level_one_companies = Company.includes(:state) 
            .where(level: 1) 
            .order('created_at DESC').limit(20) 

    @level_two_companies = Company.includes(:state) 
            .where(level: 2) 
            .order('created_at DESC').limit(20) 
end 

na stronie indeksu i będzie mieć tabele dla każdego z nich i muszę odświeżyć tabele, gdy nowe dane są dodawane do stanu (lub) Poziom 1 (lub) Poziom 2 przedsiębiorstw.

Wiem, że mogę iść z widokiem na dwa sposoby automatycznej aktualizacji tj

  1. działania Cable.
  2. Pule danych w przedziale czasu za pomocą Jquery.

Zwykle podczas korzystania z kabla Action wysyłamy dane z serwera po utworzeniu rekordu w db (po .save w akcji create (lub) after_save callback z modelu). Jednak nie tworzę żadnych rekordów za pośrednictwem aplikacji rails.

Moje pierwsze pytanie brzmi: czy w tym przypadku jest jakikolwiek sposób użyć kabla akcji?

Więc poszedłem z drugą opcją i działa dobrze. Ale robi zbyt wiele połączeń db po każdych X sekundach. Czy istnieje sposób na zmniejszenie liczby zapytań, aby zaktualizować widoki? Jaki jest najlepszy sposób, aby przejść tutaj? Każda pomoc bardzo ceniona. Dzięki.

Odpowiedz

3

jeśli twoje tagi są ustawione poprawnie, używasz PostgreSQL jako bazy danych.

Postgres oferuje machanizm subskrypcji publikowanej, którego można użyć w połączeniu z kodem akcji, aby posłuchać zmian w bazie danych.

w this gist, można znaleźć przykład postgres-pubsub z wydarzeniami wysłanymi przez serwer. powinno być proste przetłumaczenie tego na kod kompatybilny z kodem czynnościowym.

+0

Dziękuję @phoet , spróbuję i dam ci znać. –

0

Możesz utworzyć wyzwalacz w tabeli (tworzy/aktualizuje/usuwa), która uruchamia powiadomienie na "kanale", i możesz słuchać tego kanału dla zdarzeń. Używam socketcluster, słucham od pracowników i transmituję do konsumentów (przeglądarki i aplikacje mobilne).

Najpierw trzeba utworzyć wyzwalacz:

CREATE FUNCTION deletes_notify_trigger() RETURNS trigger 
    LANGUAGE plpgsql 
    AS $$ 
DECLARE 
BEGIN 
    PERFORM pg_notify('deletes_channel', ('DELETED' || ';;' || OLD.id)::text); 
    RETURN new; 
END; 
$$; 

i

CREATE TRIGGER deletes_trigger AFTER DELETE ON events FOR EACH ROW EXECUTE PROCEDURE deletes_notify_trigger(); 

Można dodać dowolny materiał, który ma w pakiety danych nadawane, w moim przypadku wystarczy identyfikator rekordu . W przypadku tworzenia i aktualizacji można wysłać cały wiersz lub tylko wybrane kolumny. Możesz również wysłać go jako JSON w PG 9.2 (jak sądzę) i wyżej. Używam 9.1, więc zgadzam się z ;; separatory.

Upewnij się, że kod zajmuje co najwyżej 10% czasu między zapytaniami, w przeciwnym razie, jeśli wykonasz złożone połączenia lub aktualizacje lub inne operacje, zauważysz znaczne spadki wydajności.Chcesz, aby było to tak proste i szybkie, jak to tylko możliwe, zachowaj je w podstawowych operacjach i wykonaj ciężkie operacje na warstwie aplikacji.

Następnie obserwator i nadawanie konsumentom (w moim węzła przypadek, socketcluster a gem pg, w twoim przypadku można użyć JS, Python, Ruby, cokolwiek chcesz)

var global_deletes = socket.subscribe('deletes_channel'); 
pg.connect(connectionString, function(err, client) { 
     client.on('notification', function(dbmsg) { 
     console.log(dbmsg.payload); 
     var payload = dbmsg.payload.split(";;"); // you can use JSON instead 

     if (payload[0] == "DELETED") { // when a DELETE is received... 
      global_deletes.publish(dbmsg.payload); 
      var tchannel = socket.subscribe('events-'+ payload[1]); // join the channel we want to broadcast 
      setTimeout(() => tchannel.publish(dbmsg.payload), 50); // send the update to all consumers 
      setTimeout(() => tchannel.unsubscribe(), 100); 
     } 
     ); 
    var query = client.query("LISTEN deletes_channel"); // turn on notifications from the server 
});