Стратегия отслеживания недавних действий пользователя

StackOverflow https://stackoverflow.com/questions/174248

Вопрос

Наш клиент хотел бы знать кто находится в сети и в настоящее время использует пользовательское приложение, которое мы написали для них.Я обсуждал это с ними, и в этом нет необходимости точный, сработает скорее предположение.

Итак, я думаю, что это 15-минутный интервал времени для определения активности пользователя.Некоторые идеи, которые у меня есть для этого, заключаются в следующем:

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

  2. Отправьте "кто находится в сети" с помощью нашего программного обеспечения в поисках ответов, это можно было бы сделать с запланированным интервалом, а затем отметьте запись пользователя текущей датой и временем для каждого полученного мной ответа.

О чем вы думаете?И как бы вы справились с этой ситуацией?

Разъяснение

Я хотел бы использовать одну и ту же архитектуру как для Windows, так и для Интернета, если это возможно.У меня есть единый уровень бизнес-логики, с которым взаимодействуют несколько пользовательских интерфейсов, это может быть Windows или Интернет.

Под Windows я бы подразумевал клиент-сервер.

Разъяснение

Я использую n-уровневую архитектуру, поэтому мои бизнес-объекты обрабатывают все взаимодействие со слоем представления.Этот уровень представления может обеспечивать работу клиент-серверного приложения Windows, веб-приложения, веб-службы и так далее.

Это приложение с небольшим трафиком, так как оно было разработано для нашего клиента, может быть, не более 100 пользователей.

Это было полезно?

Решение

Наше решение состоит в том, чтобы поддерживать таблицу "Транзакций" (которая следует за тем, что было сделано) в дополнение к нашей таблице "Сеансов" (которая следует за тем, кто был здесь).Все инструкции по ОБНОВЛЕНИЮ, ВСТАВКЕ и УДАЛЕНИЮ управляются через объект "Transaction", и каждая из этих инструкций SQL сохраняется в таблице "Transaction" после ее успешного выполнения в базе данных (в зависимости от обновленных таблиц:у нас есть возможность специально следовать некоторым таблицам и игнорировать другие).Эта таблица "Transaction" содержит другие поля, такие как transactiontType (I для ВСТАВКИ, D для УДАЛЕНИЯ, U для ОБНОВЛЕНИЯ), transactionDateTime и т.д., А также внешний ключ "SessionID", сообщающий нам, наконец, кто отправил инструкцию.С помощью некоторого кода даже возможно определить, кто, что и когда сделал (Гас создал запись в понедельник, Тим изменил цену за единицу во вторник, Лиз добавила дополнительную скидку в четверг и т.д.).

Плюсами этого решения являются:

  1. вы можете рассказать, "что, кто и когда", и показать это своим пользователям!(вам понадобится некоторый код для анализа инструкций SQL)
  2. если ваши данные реплицируются и репликация завершается с ошибкой, вы можете перестроить свою базу данных с помощью этой таблицы

Минусы заключаются в следующем

  1. 100 000 обновлений данных в месяц означают 100 000 записей в Tbl_Transaction
  2. Наконец, эта таблица, как правило, составляет 99% объема вашей базы данных

Наш выбор:все записи старше 90 дней автоматически удаляются каждое утро

Другие советы

Я уже видел, как работает стратегия 1.Конечно, сайт был небольшим.

Интересно, как такой сайт, как stackoverflow, это делает?

Они должны быть нацелены на конкретное событие, поскольку я только что прошелся по сайту, заглянул в свой профиль и все еще говорю что-то вроде последний раз видели 8 минут назад.

Я бы просто поместил таблицу записей журнала в базу данных.

Идентификатор пользователя int FK
Символ действия (3) ("вход" или "выход")
Время, дата, время

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

Если у вас есть данные сеанса, просто используйте это.Большинство систем сеансов уже имеют временные метки, поэтому срок действия сеансов, которые не использовались в течение x минут, может истечь.

Вы можете увеличивать глобальную переменную каждый раз, когда создается сеанс пользователя, и уменьшать ее при его уничтожении.Таким образом, вы будете всегда знайте, сколько пользователей находится в сети в любой данный момент.

С другой стороны, если вы хотите отслеживать это с течением времени, я думаю, что лучшим вариантом является протоколирование начала и окончания сеанса в базе данных, и вы вычисляете активность пользователя постфактум с помощью простого запроса.

[ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ 1 --- Java-решение]

Если каждому значимому пользователю предоставляется сеанс, то вы могли бы написать свою собственную реализацию SessionListener для отслеживания каждого созданного и уничтоженного сеанса.

[ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ 2 --- Код не протестирован или не скомпилирован]

public class ActiveSessionsListener implements HttpSessionListener {
    public void sessionCreated(HttpSessionEvent e) {
        ServletContext ctx = e.getSession().getServletContext();
        synchronized (ctx) {
            Integer count = ctx.getAttribute("SESSION_COUNT");
            if (count == null) { count = new Integer(0); }
            ctx.setAttribute("SESSION_COUNT", new Integer(count.intValue() + 1);
        }
    }
    public void sessionDestroyed(HttpSessionEvent e) {
        ... similar for decrement ...    
    }
}

И зарегистрируйте это в своем web.xml:

<listener-class>com.acme.ActiveSessionsListener</listener-class>

Надеюсь, это поможет.

Единственная проблема с решением для веб-приложений заключается в том, что вы часто не знаете, когда кто-то выходит из системы.Очевидно, что если у вас есть требования к входу в систему / аутентификации, вы можете фиксировать, когда человек входит в систему, и как часть вашего кода доступа к данным вы можете входить в систему, когда человек обращается к базе данных.Но вам придется смириться с тем, что не будет надежного способа захвата момента выхода пользователя из системы - многие просто уйдут с сайта, не выполнив действие "выйти из системы".

Я бы предположил, что использование триггера было бы разумным вариантом, который избавил бы вас от необходимости возиться с любыми логическими различиями между веб- и не веб-средой (или любой другой средой, если уж на то пошло).Однако это только фиксирует изменения в среде и ничего не делает при выполнении инструкций select .Однако это можно преодолеть, если все ваши команды из приложений выполняются с помощью хранимых процедур.

В случае с веб-приложением понятие "онлайн" немного расплывчато.Лучшее, что вы действительно можете сделать, это "отправил запрос за последние X минут" или, возможно, "прошел проверку подлинности за последние X минут".

Выберите набор событий (отправленный запрос, выполненное обновление, аутентификация, ...) и занесите их в таблицу базы данных.

Занесите их в таблицу в отдельной базе данных

Я работал со многими системами, которые использовали первый метод, который вы перечислили, и при небольшом тщательном планировании это может быть сделано таким образом, что на самом деле особого эффекта не будет.

Все зависит от того, когда именно / как / что вы пытаетесь отследить.Если вам нужно отслеживать несколько сеансов, я обычно вижу людей, которые используют систему сеансов, привязанную к учетной записи пользователя, а затем по истечении определенного времени этот сеанс считается мертвым.

Если вы действительно ищете что-то онлайн в данный момент, ваш первый вариант - лучший.

Я только что внедрил последнюю замеченную систему для своего веб-сайта.Ваш первый вариант похож, но я обновляю его только каждые +-5 минут.Это работает в моей ситуации, но веб-сайтам большего масштаба может потребоваться что-то немного дополнительное.

<?php
function updateLastSeen($user_ref, $session_id, $db) { /*Parameters: The user's primary key, the user's session id, the connection to the database*/
  $timestamp = date('Y-m-d H:i:s');
  if ($session_id !== '') {
    /*logged in*/
    $sql_check = "SELECT user_id FROM user_last_seen WHERE user_id = ?";
    $stmt_check = $db->prepare($sql_check);
    $stmt_check->bind_param('s', $user_ref);
    $result_check = $stmt_check->execute();
    $stmt_result_check = $stmt_check->get_result();
    if ($stmt_result_check->num_rows > 0) { /*If the user's last seen was previously recorded, update his record*/
      $sql = "UPDATE user_last_seen SET last_seen = ? WHERE user_id = ?"; 
    } else { /*Otherwise, insert a record for him*/
      $sql = "INSERT INTO user_last_seen (last_seen, user_id) VALUES (?,?)";
    }
    $stmt = $db->prepare($sql);
    $stmt->bind_param('ss', $timestamp, $user_ref);
    $result = $stmt->execute();
  }
}
if( !isset($_SESSION['lastSeen']) ){ /*User logs into the website or lands on the current page, create a lastSeen variable*/
  $_SESSION['lastSeen'] = time();
  updateLastSeen($user_ref, $session_id, $db);
} else {
  $last_seen_time_difference = (time() - $_SESSION['lastSeen']) / 60;
  if ($last_seen_time_difference > 5) { //if the difference between now and the lastSeen is 5 minutes or more, record his last seen.
    updateLastSeen($user_ref, $session_id, $db);   
    $_SESSION['lastSeen'] = time(); /*after updating the database, reset the lastSeen time to now.*/
  }/* else {
    //do nothing. Don't update database if lastSeen is less than 5 minutes ago. This prevents unnecessary database hits.
  }*/
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top