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
[MARLIN-621] Do not send previously sent immutable entities to Connec!™ #186
base: master
Are you sure you want to change the base?
[MARLIN-621] Do not send previously sent immutable entities to Connec!™ #186
Conversation
7ed659b
to
cd7ab61
Compare
… to connec if we have already sent it Eg: BankTransaction, is an immutable entity, Once we see the transactions in Marlin Banking Adapter, it doesnot change So we don't have to send the transactions again to Connec again, especially during a full_sync If the full sync is configured to run every day and if we send all transcations to connec every time, then connec gets overloaded and returns 500
cd7ab61
to
6709211
Compare
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.
I'd change the specs structure with context to make it easier to understand.
Looking a the description (eg: rspec --format doc) I see:
Maestrano::Connector::Rails::Services::DataConsolidator
#consolidate_external_entities
return all external entities
return some external entities
returns empty array
We don't know why it's returning different output. so I'd use some context (with before blocks to create the records)
Other than the specs, the code LGTM
@@ -81,6 +81,7 @@ def consolidate_external_entities(external_entities, connec_entity_name) | |||
entity_id = @current_entity.class.id_from_external_entity_hash(entity) | |||
idmap = @current_entity.class.find_or_create_idmap(external_id: entity_id, organization_id: @organization.id, connec_entity: connec_entity_name.downcase) | |||
|
|||
next if @current_entity.class.immutable? && idmap.connec_id.present? |
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.
Add a comment above and a blank line after.
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.
perhaps extract this to a public method on the Entity class (?)
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.
I think its better to extract it into private method in the same class. It doesn't belong in Entity class as it also queries idmap.
@@ -34,23 +34,37 @@ def update_external_entity(mapped_connec_entity, external_id, external_entity_na | |||
# e.g entity['id'] | |||
def self.id_from_external_entity_hash(entity) | |||
# TODO | |||
# This method return the id from external_entity_hash |
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.
I think you duplicated the doc here? See #183
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.
ya my bad, rebase conflict was resolved wrong, fixed it
|
||
def self.immutable?(entity) | ||
# TODO | ||
# This method return true if entity is immutable. |
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.
The method documentation should be above the method (see #183)
def self.immutable?(entity) | ||
# TODO | ||
# This method return true if entity is immutable. | ||
# An entity is immutable, if it is only ever creates, but never updated. eg. BankTransaction |
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.
Grammar.
An entity is immutable if it is only ever created but never updated
end | ||
|
||
describe 'consolidate_external_entities' do | ||
it 'should return all external entities' do |
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.
Do not use should
but the 3rd person in the present tense:
it 'returns all external entities'
See [betterspecs|http://www.betterspecs.org/#should]
end | ||
end | ||
|
||
describe 'consolidate_external_entities' do |
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.
describe '#consolidate_external_entities'
See [betterspecs|http://www.betterspecs.org/#describe]
Maestrano::Connector::Rails::IdMap.create(external_id: "TX8934077941420180731", external_entity: 'transaction', organization_id: organization.id, connec_entity: 'banktransaction', connec_id: 1) | ||
transaction = BankTransaction.new(organization, nil, nil) | ||
allow(BankTransaction).to receive(:immutable?).and_return(true) | ||
data_consolidator = Maestrano::Connector::Rails::Services::DataConsolidator.new(organization, transaction, {}) |
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.
used described_class
Also please edit the title of the PR as it took the first commit message and truncated it |
@@ -4,4 +4,5 @@ rvm: | |||
services: | |||
- redis-server | |||
before_install: | |||
- gem install bundler # Update bundler version | |||
- rvm @global do gem uninstall bundler -a -x | |||
- rvm @global do gem install bundler -v 1.17.3 |
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.
👍
|
||
class BankTransaction < Maestrano::Connector::Rails::Entity | ||
def self.id_from_external_entity_hash(entity) | ||
entity["id"] |
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.
single quotes
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.
overall, lgtm -- think this will be a big improvement. I Agree with Oli about clarifying the specs.
I'm also still not 100% sure if this will fix all of our load problems. The load issue seemed to be coming from a single batch call, with only 20 entities, so I think if there are more than 20 entities to sync it may still fail. Obviously this is a great start. Will also need a code change in the banking-adapter too right? |
Fixed specs, it was in bad shape. Fixed errors due to rebase conflicts. Added comment for next statement and refactored into a private method
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.
The specs could be tidied up to follow best practices. This is a public project and the one that most likely to be used for external developers so we need to be particulary attentive to the quality of the code.
I realised we don't use rubocop-rspec for this project. I'll add it to the list of further improvements
|
||
context 'entity is not immutable, no entity has been pushed to connec! before' do | ||
it 'returns all external entities' do | ||
allow(BankTransaction).to receive(:immutable?).and_return(false) |
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.
This should be in the context, eg:
context 'entity is mutable' do
before { allow(BankTransaction).to receive(:immutable?).and_return(false) }
...
end
This will make it easier to read and is good practice if you have multiple tests (only one in this case)
|
||
context 'entity is immutable and some entities have been pushed to connec! before' do | ||
it 'returns some external entities' do | ||
Maestrano::Connector::Rails::IdMap.create(external_id: 'TX8934077941420180731', external_entity: 'transaction', organization_id: organization.id, connec_entity: 'banktransaction', connec_id: 1) |
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.
Same for the creation and the stub. The context setup should be in a before block.
The it
blocks should be quite small
Especially since the immutable is repeated for the next step.
So something like this:
context 'when entity is immutable' do
before { allow(BankTransaction).to receive(:immutable?).and_return(true) }
context 'when some entities have already been pushed to connec!' do
before do
Maestrano::Connector::Rails::IdMap.create(external_id: 'TX8934077941420180731', external_entity: 'transaction', organization_id: organization.id, connec_entity: 'banktransaction', connec_id: 1)
end
it 'returns some external entities' do# Or it 'only returns the new entities'
...
# Only 1 expectation here which is clearer than the 3 separates
expect(ent).to match_array(external_entities[1], external_entities[2])
end
end
context 'when all entities have already been pushed to connec!' do
before do
...
end
it 'does not return any entities'
end
end
it 'only returns new entities' do | ||
# expect(subject.count).to eq(2) | ||
expect(subject[0]).to eq(external_entities[1]) | ||
expect(subject[1]).to eq(external_entities[2]) |
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.
match_array
didn't work?
In that case, you should still have an expectation on the count. Otherwise a rotation of the entities will pass the specs ;)
Organizing examples within contexts Using before for stubs and data setups
8bb1802
to
3f78eb7
Compare
@ouranos @hhemanth I have a major worry about this strategy. Unenroll purge and per-app purge do not delete the idmap fields. This means that if we unenroll and re-enroll, banking data won't get synced again. In order to fix this scenario we would need to add this purge. Because changes in batch size alone, still works, I think we need to implement the idmap purge before we can use this strategy. EDIT: This is NOT currently an issue because unenroll scopes to a new organization and per-app purge does not include ofx data |
I'm not convinced this is needed. See: https://maestranoteam.slack.com/archives/GECNLHD5K/p1547168285051100
Note, this idMap checking is bypassed I think thus, the idea of immutability is baked into this already as for immutable objects the updated_at in general, and the transaction_date in specific won't ever change @hhemanth @ouranos @alexmaestrano @alexmaestrano thoughts? |
@@ -81,6 +81,9 @@ def consolidate_external_entities(external_entities, connec_entity_name) | |||
entity_id = @current_entity.class.id_from_external_entity_hash(entity) | |||
idmap = @current_entity.class.find_or_create_idmap(external_id: entity_id, organization_id: @organization.id, connec_entity: connec_entity_name.downcase) | |||
|
|||
# Don't push to connec, the immutable entities which have already been pushed | |||
next if immutable_and_already_pushed_to_connec?(idmap) |
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.
I personally think this is already baked into behavior (see my main comments).
If we are convinced we need the explicitness of this immutability flag, then I would prefer to do:
next if immutable_and_already_pushed_to_connec?(idmap) && !opts[:full_sync]
or
next if immutable_and_already_pushed_to_connec?(idmap) && !opts[:forced]
or even
next if immutable_and_already_pushed_to_connec?(idmap) && !opts[:forced] && !opts[:full_sync]
So we have the option to send immutable entities to quickbooks anyway in case of data integrity issues.
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.
IMO, don't think this is necessary.
If convinced it is, we should have the ability to disable this skip
.
@ouranos
If an entity is immutable, then we should not send again to connec if we have already sent it
Eg: BankTransaction, is an immutable entity, Once we see the transactions in Marlin Banking Adapter, it doesnot change
So we don't have to send the transactions again to Connec again, especially during a full_sync
If the full sync is configured to run every day and if we send all transcations to connec every time,
then connec gets overloaded and returns 500
Spec Output