-
Notifications
You must be signed in to change notification settings - Fork 0
Endpoint and relation to track downsample datapoints. #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
58cd75b
7d54322
3280076
5b01c2d
a358e13
3b9d817
04a893d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| class DownsampledDatapoint < ApplicationRecord | ||
| belongs_to :channel | ||
|
|
||
| enum interval: { '5m' => 0, '10m' => 1, '15m' => 2 } | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| class DataPoints::DownSampledDataSerializer | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [rubocop] reported by reviewdog 🐶 |
||
| include JSONAPI::Serializer | ||
| attributes :value, :time_interval, :interval, :channel_id | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module DataPoints | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [rubocop] reported by reviewdog 🐶 |
||
| class Rollup | ||
| # | ||
| # initialize | ||
| # @params {Integer} interval | ||
| # can be used to provide a different interval | ||
| # | ||
| def initialize(interval = nil) | ||
| @interval = interval || 5 | ||
| @time_lower_bound = set_time_lower_bound | ||
| end | ||
|
|
||
| def call | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [rubocop] reported by reviewdog 🐶 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [rubocop] reported by reviewdog 🐶 |
||
| downsampled_data = [] | ||
| last_data_point_log_time = DataPoint.last.created_at | ||
| return if last_data_point_log_time < @time_lower_bound | ||
|
|
||
| while last_data_point_log_time > @time_lower_bound | ||
| channel_wise_average = DataPoint.where(created_at: @time_lower_bound..time_upper_bound) | ||
| .group(:channel_id) | ||
| .average(:value) | ||
| channel_wise_average.each do |channel_id, average| | ||
| downsampled_data << { channel_id: channel_id, | ||
| value: average.to_f, | ||
| time_interval: time_upper_bound, | ||
| created_at: Time.now.utc, | ||
| updated_at: Time.now.utc } | ||
| end | ||
|
|
||
| @time_lower_bound += interval_in_minutes | ||
| end | ||
| DownsampledDatapoint.insert_all!(downsampled_data) | ||
|
Gooner91 marked this conversation as resolved.
|
||
| end | ||
|
|
||
| private | ||
|
|
||
| # | ||
| # set_time_lower_bound | ||
| # | ||
| def set_time_lower_bound | ||
| if DownsampledDatapoint.any? | ||
| last_logged_time = DownsampledDatapoint.last.time_interval | ||
| last_logged_time + interval_in_minutes | ||
| else | ||
| DataPoint.first.created_at.floor_to(interval_in_minutes) | ||
| end | ||
| end | ||
|
|
||
| # | ||
| # time_upper_bound | ||
| # | ||
| def time_upper_bound | ||
| @time_lower_bound + interval_in_minutes | ||
| end | ||
|
|
||
| # | ||
| # interval_in_minutes | ||
| # | ||
| def interval_in_minutes | ||
| @interval.minutes | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| # Use this file to easily define all of your cron jobs. | ||
| # | ||
| # It's helpful, but not entirely necessary to understand cron before proceeding. | ||
| # http://en.wikipedia.org/wiki/Cron | ||
|
|
||
| # Example: | ||
| # | ||
| set :output, "log/cron_log.log" | ||
|
|
||
| every 2.minutes do | ||
| rake 'data_points:down_sample' | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| class CreateRollups < ActiveRecord::Migration[6.1] | ||
| def change | ||
| create_table :rollups do |t| | ||
| t.string :name, null: false | ||
| t.string :interval, null: false | ||
| t.datetime :time, null: false | ||
| t.jsonb :dimensions, null: false, default: {} | ||
| t.float :value | ||
| end | ||
| add_index :rollups, [:name, :interval, :time, :dimensions], unique: true | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| class CreateDownsampledDatapoints < ActiveRecord::Migration[6.1] | ||
| def change | ||
| create_table :downsampled_datapoints do |t| | ||
| t.references :channel | ||
| t.integer :interval | ||
| t.string :value | ||
|
|
||
| t.timestamps | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| class AddTimeIntervalToDownsapmpledDatapoints < ActiveRecord::Migration[6.1] | ||
| def change | ||
| add_column :downsampled_datapoints, :time_interval, :datetime, null: false, after: :value | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| class AddDefaultIntervalValue < ActiveRecord::Migration[6.1] | ||
| def change | ||
| change_column_default :downsampled_datapoints, :interval, 0 | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| class DropRollUpsTable < ActiveRecord::Migration[6.1] | ||
| def change | ||
| drop_table :rollups | ||
| end | ||
| end |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| # Can be executed using rails db:seed VERSION=001_sample_data_points.rb | ||
|
|
||
| # Adding dummy data_points (10 per device via channel) for different devices | ||
| # Each data_point for now is given a random float value | ||
|
|
||
| Device.all.each do |device| | ||
| channel = device.channels.sample | ||
| minute_index = 0 | ||
| 10000.times do | ||
| minute_index += 1 | ||
| DataPoint.create(channel: channel, | ||
| value: rand(1.0..999.9), | ||
| skip_broadcast: true, | ||
| created_at: Time.now + minute_index.minutes) | ||
| end | ||
| end | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -38,6 +38,10 @@ namespace :data_points do | |
| threads.map(&:join) | ||
| end | ||
|
|
||
| task down_sample: :environment do | ||
| DataPoints::Rollup.new().call | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [rubocop] reported by reviewdog 🐶 |
||
| end | ||
|
|
||
| def wait_for_migration! | ||
| loop do | ||
| ActiveRecord::Migration.check_pending! | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,14 @@ | |
| require 'rails_helper' | ||
|
|
||
| describe Api::DataPointsController, type: :controller do | ||
| let(:device) { create(:device) } | ||
| let(:channel) { create(:channel, device: device) } | ||
| let!(:down_sampled_data) do | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [rubocop] reported by reviewdog 🐶 |
||
| create_list(:downsampled_datapoint, 100, | ||
| channel: channel, | ||
| value: rand(1.0..999.9)) | ||
| end | ||
|
|
||
| describe 'GET /api/data_points' do | ||
| before do | ||
| 5.times do |index| | ||
|
|
@@ -26,4 +34,19 @@ | |
| expect(response.body).to have_json_size(3) | ||
| end | ||
| end | ||
|
|
||
| describe 'GET /api/down_sampled' do | ||
| it 'returns 20 down_sampled records per page' do | ||
| get :down_sampled, format: :json, params: { page: 1 } | ||
| parsed_response = JSON.parse(response.body)['data'] | ||
| expect(parsed_response.size).to eq(20) | ||
| end | ||
|
|
||
| it 'returns appropriate attributes' do | ||
| get :down_sampled, format: :json, params: { page: 1 } | ||
| parsed_response = JSON.parse(response.body)['data'] | ||
| expect(parsed_response.first['attributes'].keys) | ||
| .to eq(%w[value time_interval interval channel_id]) | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| FactoryBot.define do | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [rubocop] reported by reviewdog 🐶 |
||
| factory :downsampled_datapoint do | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| interval do '5m' end | ||
| time_interval { Time.current + 5.minutes } | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| require 'rails_helper' | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [rubocop] reported by reviewdog 🐶 |
||
| # frozen_string_literal: true | ||
|
|
||
| RSpec.describe DownsampledDatapoint, type: :model do | ||
| pending "add some examples to (or delete) #{__FILE__}" | ||
| end | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[rubocop] reported by reviewdog 🐶
[Correctable] Style/FrozenStringLiteralComment: Missing frozen string literal comment.