-
Notifications
You must be signed in to change notification settings - Fork 36
Reducing query counts on processing and removing 1+N queries in Admin View #118
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 7 commits
cdfd0e3
a1a92aa
195a687
64f4f28
75fece1
a621164
1ea0840
1de80ce
71cb08e
42dfc7c
c3287fa
62099a9
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 |
|---|---|---|
|
|
@@ -4,6 +4,7 @@ | |
| from django.core.management.base import BaseCommand | ||
| from django.core.management.base import CommandError | ||
| from django.core.files.storage import default_storage | ||
| from django.db import transaction | ||
| from pyas2lib import Message as AS2Message | ||
|
|
||
| from pyas2.models import Message | ||
|
|
@@ -66,13 +67,21 @@ def handle(self, *args, **options): | |
| content_type=partner.content_type, | ||
| disposition_notification_to=org.email_address or "no-reply@pyas2.com", | ||
| ) | ||
|
|
||
| message, _ = Message.objects.create_from_as2message( | ||
| as2message=as2message, | ||
| payload=payload, | ||
| filename=original_filename, | ||
| direction="OUT", | ||
| status="P", | ||
| ) | ||
|
|
||
| # Check if we're inside an atomic block, if not, commit immediately to store the message | ||
| if not transaction.get_connection().in_atomic_block: | ||
| transaction.commit() | ||
|
|
||
| message.organization = org | ||
|
Owner
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. add a comment on why you are doing this
Contributor
Author
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. will add. |
||
| message.partner = partner | ||
| message.send_message(as2message.headers, as2message.content) | ||
|
|
||
| # Delete original file if option is set | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -342,9 +342,12 @@ def create_from_as2message( | |
| if not filename: | ||
| filename = f"{uuid4()}.msg" | ||
| message.headers.save( | ||
| name=f"{filename}.header", content=ContentFile(as2message.headers_str) | ||
| name=f"{filename}.header", | ||
| content=ContentFile(as2message.headers_str), | ||
| save=False, | ||
| ) | ||
| message.payload.save(name=filename, content=ContentFile(payload)) | ||
| message.payload.save(name=filename, content=ContentFile(payload), save=False) | ||
| message.save() | ||
|
|
||
| # Save the payload to the inbox folder | ||
| full_filename = None | ||
|
|
@@ -460,6 +463,13 @@ def status_icon(self): | |
|
|
||
| def send_message(self, header, payload): | ||
| """Send the message to the partner""" | ||
|
|
||
| if self.organization_id and self.partner_id: | ||
| self.organization = self.organization or Organization.objects.get( | ||
|
Owner
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. reason for this change?
Contributor
Author
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. I have noted that under certain circumstances (i.e. update_or_create) will not keep the related object inside the model. So, in case that this is happening, then we pull it once more, but we are not pulling it, when it exists already, thus not executing another query. |
||
| id=self.organization_id | ||
| ) | ||
| self.partner = self.partner or Partner.objects.get(id=self.partner_id) | ||
|
|
||
| logger.info( | ||
| f'Sending message {self.message_id} from organization "{self.organization}" ' | ||
| f'to partner "{self.partner}".' | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,22 +2,23 @@ | |
| from email.parser import HeaderParser | ||
| from unittest import mock | ||
|
|
||
| from django.test import TestCase, Client | ||
| from django.db import connection | ||
| from django.test import Client, TestCase | ||
| from django.test.utils import CaptureQueriesContext | ||
| from pyas2lib.as2 import Message as As2Message | ||
| from requests import Response | ||
| from requests.exceptions import RequestException | ||
|
|
||
| from pyas2.models import ( | ||
| PrivateKey, | ||
| PublicCertificate, | ||
| Mdn, | ||
| Message, | ||
| Organization, | ||
| Partner, | ||
| Message, | ||
| Mdn, | ||
| PrivateKey, | ||
| PublicCertificate, | ||
| ) | ||
| from pyas2.tests import TEST_DIR | ||
|
|
||
| from pyas2lib.as2 import Message as As2Message | ||
|
|
||
|
|
||
| class BasicServerClientTestCase(TestCase): | ||
| """Test cases for the AS2 server and client. | ||
|
|
@@ -534,6 +535,29 @@ def testEncryptSignMessageAsyncSignMdn(self, mock_request): | |
| mock_request.side_effect = RequestException() | ||
| out_message.mdn.send_async_mdn() | ||
|
|
||
| def testNumberOfQueries(self): | ||
| """Testing against the number of queries executed""" | ||
|
|
||
| # Create the partner with appropriate settings for this case | ||
|
|
||
| partner = Partner.objects.create( | ||
| name="AS2 Server", | ||
| as2_name="as2server", | ||
| target_url="http://localhost:8080/pyas2/as2receive", | ||
| mdn=False, | ||
| ) | ||
|
|
||
| with CaptureQueriesContext(connection) as queries: | ||
| in_message = self.build_and_send(partner) | ||
|
|
||
| # Remove the transaction related queries | ||
| filtered_queries = [ | ||
| query for query in queries if "SAVEPOINT" not in query["sql"] | ||
| ] | ||
|
|
||
| # number of queries should be 9 | ||
|
||
| self.assertEqual(len(filtered_queries), 13) | ||
|
|
||
| @mock.patch("requests.post") | ||
| def build_and_send(self, partner, mock_request): | ||
| # Build and send the message to server | ||
|
|
||
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.
what is the reason for this change?
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 had this in my branch and was a left over from here #45. Issue is, the message is not stored before sending, and if partner sends an MDN back before the message is commited to DB, then the MDN fails and triggers a "no message found" error. This should prevent this.
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 reason for this is, because tests fun in atomic transaction and therefore this will fail. The behavior of the django test is different than when running the command "normally". transaction.commit() would fail if running inside an atomic 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.
We should not be writing code to handle for tests, this needs to be handled differently. Can be picked later
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.
We don't know how anyone would be using this command - someone might wrap this command in an atomic transaction which would then fail this too probably. So I don't see this as "for tests"...
Originally I was going to use a config flag if we are in test mode or not, but then we even have more "only test specific" code.
Let me know if you want me to simple remove this from this PR, then I will and you can decide at a later point how you want this.
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.
lets move it out of the PR
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.
done