Проблемы с использованием контроллера в Postgres DB на AWS RDS из приложения Heroku
Я настроил базу данных postgres для использования postgis для моего приложения Heroku, работающего на Ruby on Rails.
Мои шаги были:
- Создать БД RDS под управлением pg 9.4.9
- Включите rds.force_ssl в группе параметров RDS.
- Сделайте резервную копию и загрузите мою базу данных Heroku в новую базу данных postgres.
- Загрузите Сертификат Amazon RDS CA и поместите его в config/amazon-rds-ca-cert.pem.
- Добавьте gem 'activerecord-postgis-adapter' в мой файл gem.
- Обновите файл database.yml до следующего:
:
default: &default
adapter: postgis
encoding: unicode
pool: 5
production:
<<: *default
encoding: utf8
database: <%= ENV['RDS_DB_NAME'] %>
username: <%= ENV['RDS_USERNAME'] %>
password: <%= ENV['RDS_PASSWORD'] %>
host: <%= ENV['RDS_HOSTNAME'] %>
port: <%= ENV['RDS_PORT'] %>
postgis_extension: postgis
schema_search_path: public,postgis
- Обновите параметр DATABASE_URL в Heroku до postgres://myuser:mypassword@mydbinstance.xxxxxxxxxxx.us-west-2.rds.amazonaws.com/mydbname? Sslmode=verify-full&sslrootcert=config/amazon-rds-ca-cert.pem
- Дополнительные шаги в этом очень полезном вопросе: Включение поддержки Ruby PostGIS в Heroku
- Нажмите обновленный код и получите доступ к моему приложению.
Когда я пытаюсь получить доступ к базе данных для проверки подключения, она работает нормально:
nc -zv mydbinstance.xxxxxxxx.us-west-2.rds.amazonaws.com 5432
Connection to mydbinstance.xxxxxxxxx.us-west-2.rds.amazonaws.com 5432 port [tcp/postgresql] succeeded!
и когда я перемещаюсь по приложению, я могу видеть результаты запросов. Однако, когда я пытаюсь использовать модель, которая использует postgis, мои соединения почему-то работают неправильно. Вот код моего контроллера, который хранит пары lat, lng с информацией об автобусной остановке и находит те, которые близки к точке, заданной в параметрах:
class TransitStopsController < ApplicationController
def create
end
def show
@transit_stop = TransitStop.find(params[:id])
@transit_routes = @transit_stop.transit_routes
end
def get_nearby_stops
radius_in_meters = params[:radius_in_meters].nil? ? 3219 : params[:radius_in_meters]
@nearby_stops = TransitStop.close_to(params[:lat], params[:lng], radius_in_meters)
end
end
Моя модель:
class TransitStop < ActiveRecord::Base
has_many :transit_stops_transit_routes, foreign_key: "onestop_id", class_name: "TransitStopsTransitRoute"
has_many :transit_routes, through: :transit_stops_transit_routes, foreign_key: "route_onestop_id", class_name: "TransitRoute"
validates_uniqueness_of :onestop_id
#Get transit stops close to a given lat, lng pair. Default distance = 2 miles
scope :close_to, -> (lat, lng, distance_in_meters = 3219) {
where(%{
ST_DWithin(
ST_GeographyFromText(
'SRID=4326;POINT(' || transit_stops.lng || ' ' || transit_stops.lat || ')'
),
ST_GeographyFromText('SRID=4326;POINT(%f %f)'),
%d
)
} % [lng, lat, distance_in_meters])
}
end
и мой вид (get_nearby_stops.jbuilder):
json.nearby_stops @nearby_stops do |transit_stop|
json.region_id transit_stop.region_id
json.lat transit_stop.lat
json.lng transit_stop.lng
json.onestop_id transit_stop.onestop_id
json.name transit_stop.name
json.osm_way_id transit_stop.osm_way_id
json.osm_way_id transit_stop.served_by_vehicle_types
json.timezone transit_stop.timezone
json.wheelchair_boarding transit_stop.wheelchair_boarding
json.created_or_updated_in_changeset_id transit_stop.created_or_updated_in_changeset_id
json.transit_routes transit_stop.transit_routes
end
Routes.rb добавил строку в метод доступа:
get 'transit_stops/get_nearby_stops' => 'transit_stops#get_nearby_stops'
Когда я пытаюсь получить доступ к этому через: https://myherokuapp.herokuapp.com/transit_stops/get_nearby_stops.json?lat=-122.49766&lng=37.71677
Все, что я получаю, это сообщение:
Ошибка приложения
В приложении произошла ошибка, и ваша страница не может быть обработана. Если вы являетесь владельцем приложения, проверьте подробности в своих журналах.
Когда я просматриваю логи моей героки, я вижу только ошибку тайм-аута:
app[web.1]: Processing by TransitStopsController#get_nearby_stops as JSON
app[web.1]: Parameters: {"lat"=>"-122.49766", "lng"=>"37.71677"}
heroku[router]: at=error code=H12 desc="Request timeout" method=GET path="/transit_stops/get_nearby_stops.json?lat=-122.49766&lng=37.71677" host=myherokuapp.herokuapp.com request_id=1e081fdf-d0ce-4000-a6b4-4e75c176b8a2 fwd="10.0.0.1" dyno=web.1 connect=0ms service=30001ms status=503 bytes=0
Журналы ошибок AWS ничего не показывают.
Странно для меня то, что я могу выполнить тот же запрос, подключившись к консоли рельсов Heroku:
irb(main):001:0> TransitStop.close_to(-122.49766,37.71677,5000)
=> #<ActiveRecord::Relation [#<TransitStop region_id: 1, lat: #<BigDecimal:7fe69f6c95c0,'-0.122504106E3',18(18)>...
...
etc
Так что на данный момент я не понимаю, что вызывает сбой этого контроллера, только когда я получаю к нему доступ через мой взгляд, но не через консоль? Должен ли URL базы данных быть другим, если я использую методы postgis?
Любая помощь будет высоко оценен.
РЕДАКТИРОВАТЬ: Я протестировал метод шоу моего контроллера, и он работает нормально:
app<a class="jive-link-external" href="http://web.1">http://web.1</a>: Started GET "/transit_stops/s-9q8ys6puje-655johnmuirave.json" for 159.16.243.2 at 2016-11-12 19:55:16 +0000
app<a class="jive-link-external" href="http://web.1">http://web.1</a>: Processing by TransitStopsController#show as JSON
app<a class="jive-link-external" href="http://web.1">http://web.1</a>: Parameters: {"id"=>"s-9q8ys6puje-655johnmuirave"}
heroku<a href="https://forums.aws.amazon.com/">router</a>: at=info method=GET path="/transit_stops/s-9q8ys6puje-655johnmuirave.json" host=myapp.herokuapp.com request_id=15814367-5235-484b-bff9-7727a2349dd0 fwd="10.0.0.1" dyno=web.1 connect=0ms service=329ms status=200 bytes=1385
app<a class="jive-link-external" href="http://web.1">http://web.1</a>: Rendered transit_stops/show.json.jbuilder (107.3ms)
app<a class="jive-link-external" href="http://web.1">http://web.1</a>: Completed 200 OK in 217ms (Views: 6.7ms | ActiveRecord: 207.4ms)<br class="jive-newline" />
Что для меня означает, что в базе данных возникли проблемы с выполнением запроса, который я делаю? Сам запрос должен быть быстрым, поскольку, когда я тестирую его в консоли, я всегда получаю ответ почти сразу, но, возможно, что-то в конфигурации базы данных необходимо изменить?
1 ответ
Просто для того, чтобы другие люди увидели, моя проблема заключалась в том, что после запроса мое представление также производило несколько дополнительных запросов, потому что поле
transit_stop.transit_routes
это отношение к другой таблице. Таким образом, для каждой результирующей остановки база данных выполняла много других запросов для каждого полученного мной результата. Так как мой запрос возвращал несколько сотен результатов, окончательное представление выполнило несколько сотен дополнительных запросов, что вызвало большие накладные расходы для моей базы данных.
Чтобы обнаружить это, я обновил log_statement = all в моей группе параметров базы данных, чтобы я мог видеть всю активность, поступающую в базу данных. Я обновил свой запрос, чтобы сделать его более эффективным, сократив количество результатов только до n ближайших, максимум до 10, так как я на самом деле не имею никакого смысла получать так много результатов.