Skip to content
Snippets Groups Projects
Unverified Commit 8cbf7825 authored by Samuel Couillard's avatar Samuel Couillard Committed by GitHub
Browse files

Improvements for handling missed "meeting_ended" and "recording_ready" callbacks (#5327)

* Initial commit

* Remove unused files

* Improvements in error handling, refactoring

* add running_meeting_checker spec

* improve recordings_poller

* remove provider scoping, improve code with logs

* rubo

* Fix Dockerfile, docker-compose

* fix logs issue

* remove database name from docker-compose

* Rework poller script to match start script

* Put proper image to docker-compose
parent 6fb226cd
Branches
Tags
No related merge requests found
......@@ -40,7 +40,8 @@ RUN apk update \
COPY . ./
RUN apk update \
&& apk upgrade \
&& update-ca-certificates
&& update-ca-certificates \
&& chmod +x ./bin/poller
EXPOSE ${PORT}
ENTRYPOINT [ "./bin/start" ]
......@@ -40,7 +40,8 @@ module Api
# Returns a list of the current_user's rooms and shared rooms
def index
shared_rooms = SharedAccess.where(user_id: current_user.id).select(:room_id)
rooms = Room.where(user_id: current_user.id)
rooms = Room.includes(:user)
.where(user_id: current_user.id)
.or(Room.where(id: shared_rooms))
.order(online: :desc)
.order('last_session DESC NULLS LAST')
......@@ -50,7 +51,7 @@ module Api
room.shared = true if room.user_id != current_user.id
end
RunningMeetingChecker.new(rooms:, provider: current_provider).call
RunningMeetingChecker.new(rooms:).call
render_data data: rooms, status: :ok
end
......@@ -58,7 +59,7 @@ module Api
# GET /api/v1/rooms/:friendly_id.json
# Returns the info on a specific room
def show
RunningMeetingChecker.new(rooms: @room, provider: current_provider).call if @room.online
RunningMeetingChecker.new(rooms: @room).call if @room.online
@room.shared = current_user.shared_rooms.include?(@room)
......
......@@ -18,19 +18,19 @@
# Pass the room(s) to the service and it will confirm if the meeting is online or not and will return the # of participants
class RunningMeetingChecker
def initialize(rooms:, provider:)
def initialize(rooms:)
@rooms = rooms
@provider = provider
end
def call
online_rooms = Array(@rooms).select { |room| room.online == true }
online_rooms.each do |online_room|
bbb_meeting = BigBlueButtonApi.new(provider: @provider).get_meeting_info(meeting_id: online_room.meeting_id)
bbb_meeting = BigBlueButtonApi.new(provider: online_room.user.provider).get_meeting_info(meeting_id: online_room.meeting_id)
online_room.participants = bbb_meeting[:participantCount]
rescue BigBlueButton::BigBlueButtonException
online_room.update(online: false)
next
end
end
end
# Set default port if PORT is not set
PORT="${PORT:=3000}"
# Parse Rails DATABASE and REDIS urls to get host and port
TXADDR=${DATABASE_URL/*:\/\/}
TXADDR=${TXADDR/*@/}
TXADDR=${TXADDR/\/*/}
IFS=: TXADDR=($TXADDR) IFS=' '
PGHOST=${TXADDR[0]}
PGPORT=${TXADDR[1]:-5432}
TXADDR=${REDIS_URL/*:\/\/}
TXADDR=${TXADDR/*@/}
TXADDR=${TXADDR/\/*/}
IFS=: TXADDR=($TXADDR) IFS=' '
RDHOST=${TXADDR[0]}
RDPORT=${TXADDR[1]:-6379}
#!/usr/bin/env bash
source config.env
if [ "$RAILS_ENV" = "production" ]; then
while ! nc -zw3 $PGHOST $PGPORT
do
echo "Waiting for postgres to start up ..."
sleep 1
done
fi
bundle exec rake poller:run_all
#!/usr/bin/env bash
PORT="${PORT:=3000}"
# Parse Rails DATABASE and REDIS urls to get host and port
TXADDR=${DATABASE_URL/*:\/\/}
TXADDR=${TXADDR/*@/}
TXADDR=${TXADDR/\/*/}
IFS=: TXADDR=($TXADDR) IFS=' '
PGHOST=${TXADDR[0]}
PGPORT=${TXADDR[1]:-5432}
TXADDR=${REDIS_URL/*:\/\/}
TXADDR=${TXADDR/*@/}
TXADDR=${TXADDR/\/*/}
IFS=: TXADDR=($TXADDR) IFS=' '
RDHOST=${TXADDR[0]}
RDPORT=${TXADDR[1]:-6379}
source config.env
echo "Greenlight-v3 starting on port: $PORT"
......
......@@ -136,6 +136,7 @@ Rails.application.configure do
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name")
if ENV['RAILS_LOG_TO_STDOUT'].present?
$stdout.sync = true
logger = ActiveSupport::Logger.new($stdout)
logger.formatter = config.log_formatter
config.logger = ActiveSupport::TaggedLogging.new(logger)
......
......@@ -33,3 +33,13 @@ services:
depends_on:
- postgres
- redis
greenlight-v3-poller:
entrypoint: [bin/poller]
image: bigbluebutton/greenlight:v3
container_name: greenlight-v3-poller
env_file: .env
depends_on:
- postgres
- redis
# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
#
# Copyright (c) 2022 BigBlueButton Inc. and by respective authors (see below).
#
# This program is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free Software
# Foundation; either version 3.0 of the License, or (at your option) any later
# version.
#
# Greenlight is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with Greenlight; if not, see <http://www.gnu.org/licenses/>.
# frozen_string_literal: true
namespace :poller do
desc 'Runs all pollers'
task :run_all, %i[interval] => :environment do |_task, args|
args.with_defaults(interval: 30)
interval = args[:interval].to_i.minutes # set the interval in minutes
poller_tasks = %w[poller:meetings_poller poller:recordings_poller]
info "Running poller with interval #{interval}"
loop do
poller_tasks.each do |poller_task|
info "Running #{poller_task} at #{Time.zone.now}"
Rake::Task[poller_task].invoke(interval)
rescue StandardError => e
err "An error occurred in #{poller_task}: #{e.message}. Continuing..."
end
sleep interval
poller_tasks.each do |poller_task|
Rake::Task[poller_task].reenable
end
end
end
desc 'Polls meetings to check if they are still online'
task meetings_poller: :environment do
online_meetings = Room.includes(:user).where(online: true)
RunningMeetingChecker.new(rooms: online_meetings).call
rescue StandardError => e
err "Unable to poll meetings. Error: #{e}"
end
desc 'Polls recordings to check if they have been created in GL'
task :recordings_poller, %i[interval] => :environment do |_task, args|
# Returns the providers which have recordings disabled
disabled_recordings = RoomsConfiguration.joins(:meeting_option).where(meeting_option: { name: 'record' }, value: 'false').pluck(:provider)
# Returns the rooms which have been online recently and have not been recorded yet
recent_meeting_interval = args[:interval] * 2
recent_meetings = Room.includes(:user)
.where(last_session: recent_meeting_interval.ago..Time.zone.now, online: false)
.where.not(user: { provider: disabled_recordings })
recent_meetings.each do |meeting|
recordings = BigBlueButtonApi.new(provider: meeting.user.provider).get_recordings(meeting_ids: meeting.meeting_id)
recordings[:recordings].each do |recording|
next if Recording.exists?(record_id: recording[:recordID])
unless meeting.recordings_processing.zero?
meeting.update(recordings_processing: meeting.recordings_processing - 1) # cond. in case both callbacks fail
end
RecordingCreator.new(recording:).call
rescue StandardError => e
err "Unable to poll Recording:\nRecordID: #{recording[:recordID]}\nError: #{e}"
next
end
end
end
end
# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
#
# Copyright (c) 2022 BigBlueButton Inc. and by respective authors (see below).
#
# This program is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free Software
# Foundation; either version 3.0 of the License, or (at your option) any later
# version.
#
# Greenlight is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with Greenlight; if not, see <http://www.gnu.org/licenses/>.
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe RunningMeetingChecker, type: :service do
let!(:online_room) { create(:room, online: true, user: create(:user, provider: 'greenlight')) }
let(:bbb_api) { instance_double(BigBlueButtonApi) }
before do
allow(BigBlueButtonApi).to receive(:new).and_return(bbb_api)
end
context 'when the meeting is running' do
let(:bbb_response) do
{
running: true
}
end
it 'updates the online status to true' do
allow(bbb_api).to receive(:get_meeting_info).and_return(bbb_response)
described_class.new(rooms: Room.all).call
expect(online_room.reload.online).to eq(bbb_response[:running])
end
end
context 'when the meeting is not running' do
it 'updates the online status to false' do
allow(bbb_api).to receive(:get_meeting_info).and_raise(BigBlueButton::BigBlueButtonException)
described_class.new(rooms: Room.all).call
expect(online_room.reload.online).to be_falsey
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment