-
Notifications
You must be signed in to change notification settings - Fork 29
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
Conversation
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.
Jedno pytanie. Poza tym super
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 forget to update Swagger. :-)
functions/send_encounters/README.md
Outdated
@@ -0,0 +1,58 @@ | |||
# Get status endpoint |
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 guess it is a copy-paste from another file. Could we fix it?
functions/send_encounters/README.md
Outdated
device_name | ||
app_version | ||
lang | ||
encounters |
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.
Could it be better to list encounter
fields with datatypes?
functions/send_encounters/main.py
Outdated
|
||
def send_encounters(request): | ||
if not request.is_json: | ||
return jsonify( |
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.
It would be better to unify formatting. See this line and 28, for example.
functions/send_encounters/main.py
Outdated
|
||
request_data = request.get_json() | ||
|
||
for key in ["user_id", "platform", "os_version", "device_type", "app_version", "lang", "encounters"]: |
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.
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.
functions/send_encounters/main.py
Outdated
} | ||
), 422 | ||
|
||
user_id = request_data["user_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.
It is better to use constants for the names of all request fields.
functions/send_encounters/main.py
Outdated
), 401 | ||
rows_to_insert = [] | ||
for encounter in encounters: | ||
for key in ["encounter_date", "beacon_id", "signal_strength"]: |
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.
Could move all validation to functions. It is better to keep the function as clear as possible.
refaktoryzacja walidacji zapytania
a594cf9
to
f7f00aa
Compare
@arsoba thanks for review, I guess all your remarks are reflected in current, not WIP version ;) PTAL |
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.
(proszę o informację czy reviews z zewnątrz są mile widziane 😉 )
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) |
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.
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
).
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.
Nie jest to trywialne w kontekście CF, ale mamy to w planach ;)
functions/send_encounters/main.py
Outdated
} | ||
) | ||
|
||
for encounter in request_data["encounters"]: |
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.
W przypadku gdy lista jest pusta, funkcja nie powinna się zakończyć (z błędem lub bez)?
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.
słuszna uwaga, dzięki 👍
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.
poprawione w 359d153
) | ||
) | ||
|
||
errors = bq_client.insert_rows(table, rows_to_insert) |
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.
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.
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.
Dzięki za info - czy mógłbyś proszę przekuć to w Issue? Zajmiemy się tym wkrótce.
@bartekn dzięki za review - jasne, że są mile widziane |
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.
Wygląda bardzo dobrze. Dzięki @DariuszAniszewski
functions/send_encounters/main.py
Outdated
except InvalidRequestException as e: | ||
return jsonify( | ||
e.response, | ||
e.status |
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.
Shouldn't this be:
return jsonify(e.response), e.status
?
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.
Yes! Thanks!
|
||
[Swagger](https://swagger.io/) file is available [here](../../docs/swagger.yaml). | ||
|
||
### Deployment |
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.
Można zaznaczyć, że to jest deployment do testów. Wdrażanie powinno odbywać się przez terraforma.
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.
Pomysł OK, ale zrobiłbym to w osobnym PR - póki co jest spójne z innymi readme
functions/send_encounters/main.py
Outdated
if not request_data[key]: | ||
raise InvalidRequestException(422, {"status": "failed", "message": f"empty field: {key}"}) | ||
|
||
for encounter in request_data["encounters"]: |
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.
skoro mamy już KEY_ENCOUNTERS
to można go tu użyć
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.
jasne, dzięki!
functions/send_encounters/main.py
Outdated
{ | ||
"user_id": user_id, | ||
"upload_id": upload_id, | ||
"date": datetime.utcnow(), |
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.
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)
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.
👍
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.
Datastore przechowuje daty w UTC więc datetime.utcnow()
jest poprawne.
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.
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
…a aktualnego czasu
Rozwiązuje #7