Skip to content
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

API /send_encounters #34

Merged
merged 10 commits into from
Apr 7, 2020
Merged

API /send_encounters #34

merged 10 commits into from
Apr 7, 2020

Conversation

DariuszAniszewski
Copy link

@DariuszAniszewski DariuszAniszewski commented Apr 2, 2020

Rozwiązuje #7

@DariuszAniszewski DariuszAniszewski changed the title API /send_encounters [WIP] API /send_encounters Apr 2, 2020
jakublipinski
jakublipinski previously approved these changes Apr 3, 2020
Copy link

@jakublipinski jakublipinski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jedno pytanie. Poza tym super

functions/send_encounters/main.py Outdated Show resolved Hide resolved
Copy link

@arsoba arsoba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not forget to update Swagger. :-)

@@ -0,0 +1,58 @@
# Get status endpoint
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it is a copy-paste from another file. Could we fix it?

device_name
app_version
lang
encounters
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could it be better to list encounter fields with datatypes?


def send_encounters(request):
if not request.is_json:
return jsonify(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to unify formatting. See this line and 28, for example.


request_data = request.get_json()

for key in ["user_id", "platform", "os_version", "device_type", "app_version", "lang", "encounters"]:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have to be careful using user_id from the request. It would be difficult to generate the existing user_id, but it is really easy to leak this data.

}
), 422

user_id = request_data["user_id"]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is better to use constants for the names of all request fields.

), 401
rows_to_insert = []
for encounter in encounters:
for key in ["encounter_date", "beacon_id", "signal_strength"]:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could move all validation to functions. It is better to keep the function as clear as possible.

refaktoryzacja walidacji zapytania
@DariuszAniszewski DariuszAniszewski marked this pull request as ready for review April 4, 2020 10:12
@DariuszAniszewski DariuszAniszewski changed the title [WIP] API /send_encounters API /send_encounters Apr 4, 2020
@DariuszAniszewski
Copy link
Author

@arsoba thanks for review, I guess all your remarks are reflected in current, not WIP version ;) PTAL

@DariuszAniszewski DariuszAniszewski requested review from jakublipinski and removed request for TobKed April 4, 2020 10:15
Copy link

@bartekn bartekn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(proszę o informację czy reviews z zewnątrz są mile widziane 😉 )

Comment on lines +110 to +112
def _get_user_entity(user_id: str) -> Optional[Entity]:
device_key = datastore_client.key(USERS_DATASTORE_KIND, f"{user_id}")
return datastore_client.get(key=device_key)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ta i podobne funkcje są zduplikowane w innych plikach. Może warto przenieść je w jedno miejsce. Nie wiem na ile Google CF pozwala na takie coś. Podobnie ze stałymi (takie same w /get_status).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nie jest to trywialne w kontekście CF, ale mamy to w planach ;)

}
)

for encounter in request_data["encounters"]:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

W przypadku gdy lista jest pusta, funkcja nie powinna się zakończyć (z błędem lub bez)?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

słuszna uwaga, dzięki 👍

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

poprawione w 359d153

)
)

errors = bq_client.insert_rows(table, rows_to_insert)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Na stronie Quotas and Limits można znaleźć informację o maksymalnym rozmiarze requestu HTTP w przypadku Streaming inserts (używane przez insert_rows):

HTTP request size limit: 10 MB (see Note)
Exceeding this value will cause invalid errors.
Note: Internally the request is translated from HTTP json into an internal data structure. The translated data structure has its own enforced size limit. It's hard to predict the size of the resulting internal data structure, but the chance of hitting the internal limit is very low if you keep your HTTP requests to 5 MB or less.

Oczywiście 5 MB to sporo i jest szansa że to nigdy się nie wydarzy (zależy jak działa aplikacja mobilna) ale myślę, że z uwagi na fakt, że te dane są niezwykle ważne i nie wiadomo kiedy i czy nastąpi retry warto rozważyć trzymanie się limitu 5 MB przy dodawaniu tych danych. W praktyce trzeba wywołać insert_rows kilka razy z mniejszymi paczkami.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dzięki za info - czy mógłbyś proszę przekuć to w Issue? Zajmiemy się tym wkrótce.

@DariuszAniszewski
Copy link
Author

@bartekn dzięki za review - jasne, że są mile widziane

jakublipinski
jakublipinski previously approved these changes Apr 5, 2020
Copy link

@jakublipinski jakublipinski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wygląda bardzo dobrze. Dzięki @DariuszAniszewski

except InvalidRequestException as e:
return jsonify(
e.response,
e.status
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be:

return jsonify(e.response), e.status

?

Copy link
Author

@DariuszAniszewski DariuszAniszewski Apr 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! Thanks!


[Swagger](https://swagger.io/) file is available [here](../../docs/swagger.yaml).

### Deployment
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Można zaznaczyć, że to jest deployment do testów. Wdrażanie powinno odbywać się przez terraforma.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pomysł OK, ale zrobiłbym to w osobnym PR - póki co jest spójne z innymi readme

if not request_data[key]:
raise InvalidRequestException(422, {"status": "failed", "message": f"empty field: {key}"})

for encounter in request_data["encounters"]:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

skoro mamy już KEY_ENCOUNTERS to można go tu użyć

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jasne, dzięki!

{
"user_id": user_id,
"upload_id": upload_id,
"date": datetime.utcnow(),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taka data może zostać potraktowana jako czas lokalny podczas zapisywania do datastore. Może lepiej używać dat ze strefą czasową datetime.now(tz=pytz.utc)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Datastore przechowuje daty w UTC więc datetime.utcnow() jest poprawne.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jest poprawne o ile funkcja nie działa w innej strefie czasowej gdzie datetime.utcnow() mogłoby zostać potraktowane jako czas lokalny z tej strefy. https://docs.python.org/3/library/datetime.html#datetime.datetime.utcnow

@DariuszAniszewski DariuszAniszewski merged commit 2594507 into master Apr 7, 2020
@DariuszAniszewski DariuszAniszewski deleted the send-encounters branch April 7, 2020 07:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants