I've setup a postgres DB to use postgis for a Heroku App I have, running on Ruby on Rails.
My steps have been:
:
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
When I try to access the database to verify connectivity it works ok:
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!
and when I navigate on the app I am able to see the results of queries. However, when I try to use a model that uses postgis, somehow my connections don't work correctly. Here's my Controller's code, which stores lat, lng pairs with bus stop information, and finds the ones close to a point given in parameters:
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
My Model:
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
and my View (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 has line added to access method:
get 'transit_stops/get_nearby_stops' => 'transit_stops#get_nearby_stops'
When I try to access this via: https://myherokuapp.herokuapp.com/transit_stops/get_nearby_stops.json?lat=-122.49766&lng=37.71677
All I get is a message:
Application Error
An error occurred in the application and your page could not be served. If you are the application owner, check your logs for details.
When I look at my heroku logs all I see is a timeout error:
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
The AWS Error Logs show nothing.
The strange thing to me is that I am able to perform the same query by connecting to Heroku's rails console:
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
So at this point I don't understand what's causing this controller to fail only when I access it through my view, but not through console? Should the database url be different if I use postgis methods?
Any help would be highly appreciated.
EDIT: I've tested the show method of my controller, and it works ok:
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" />
Which to me translates to perhaps there being some problem in the database to perform the query I'm doing? The query itself should be fast, as when I test it in console I always get a response almost immediately, but perhaps something about the configuration of the database needs to be changed?
Just for other people to see, my problem was that after the query, my view was also producing several additional queries, because the field
transit_stop.transit_routes
is a relationship to a different table. Thus, for every resulting stop the database was performing many other queries for every result I got. Since my query was returning several hundred results, the final view performed several hundred additional queries which caused a lot of overhead to my db.
To detect this I updated log_statement = all to my db parameter group, so that I could see all activity coming into the database. I've updated my query to make it more efficient by reducing the number of results to only the n nearest ones, with a maximum of 10, as I don't really have any use on getting so many results.