Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
production
building-knowledge-centre
building-dao
Commits
3d684c94
Commit
3d684c94
authored
Oct 09, 2020
by
unknown
Browse files
Handle VersionConflictError at _req level, and improve doc
parent
89136881
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
72 additions
and
41 deletions
+72
-41
building_dao/building_generic.py
building_dao/building_generic.py
+61
-37
building_dao/settings.py
building_dao/settings.py
+11
-4
No files found.
building_dao/building_generic.py
View file @
3d684c94
import
logging
import
inspect
from
base64
import
b64encode
from
os.path
import
join
from
typing
import
Optional
...
...
@@ -13,13 +14,31 @@ from .settings import Settings
MAX_RETRIES
=
5
# max retries number
WAIT_BETWEEN_RETRIES_IN_MS
=
200
# time between each retry
class
VersionConflictError
(
Exception
):
"""Raised when there is a version conflict when updating ES doc"""
pass
class
BuildingGeneric
:
"""Stores the methods used to receive or update the building info from ES doc"""
"""
Stores the methods used to receive or update the building info from ES doc
There are diferent levels for requesting:
=> req_with_retry : request again on error. To be used for GET essentially
=> update_with_version: pass the version of the ES doc to the payload.
To be used:
=> for operations related to parts of doc that risk to be erased concurrently
=> whenever there is a risk that the doc gets updated by the time the request get caught by the BKC API
(since a fetch operation is done within the BKC API)
Eg: to be used for facade update
Note: for all put methods, the version is included in the payload at the BKC API level, if not provided at the worker level (ie here)
This way, a VersionConflictError pops whenever a conflicts of versions happens
"""
def
__init__
(
self
,
uid
:
str
=
None
,
**
kwargs
)
->
None
:
...
...
@@ -30,15 +49,15 @@ class BuildingGeneric:
self
.
_uid
=
uid
self
.
_building
=
None
self
.
settings
=
Settings
(
staging
=
staging
,
registry
=
registry
)
self
.
settings
=
Settings
(
staging
=
staging
,
registry
=
registry
,
**
kwargs
)
if
self
.
_uid
:
self
.
fetch
()
self
.
fetch
(
timeout
=
kwargs
.
get
(
"timeout"
,
None
)
)
def
__getitem__
(
self
,
item
):
return
self
.
_building
.
get
(
item
,
None
)
def
__setitem__
(
self
,
key
,
item
):
def
__setitem__
(
self
,
key
,
item
):
self
.
_building
[
key
]
=
item
# ----------------- Building level ---------------------
...
...
@@ -57,9 +76,11 @@ class BuildingGeneric:
buildings
=
self
.
_req_with_retries
(
"get"
,
self
.
settings
.
base_url
,
**
kwargs
)
return
buildings
def
fetch
(
self
)
->
None
:
def
fetch
(
self
,
**
kwargs
)
->
None
:
"""Fetch the building document"""
self
.
_building
=
self
.
_req_with_retries
(
"get"
,
"/"
.
join
([
self
.
settings
.
base_url
,
self
.
_uid
]))
self
.
_building
=
self
.
_req_with_retries
(
"get"
,
"/"
.
join
([
self
.
settings
.
base_url
,
self
.
_uid
]),
**
kwargs
)
def
update_building
(
self
,
payload
)
->
None
:
"""
...
...
@@ -68,14 +89,15 @@ class BuildingGeneric:
"""
self
.
_req
(
"put"
,
"/"
.
join
([
self
.
settings
.
base_url
,
self
.
_uid
]),
json
=
payload
)
def
update_status_history
(
self
,
status
:
str
)
->
None
:
def
update_status_history
(
self
,
status
:
str
,
**
kwargs
)
->
None
:
"""
Update the history.
Note: the retries for conflict error are managed within BKC API
"""
payload
=
{
"new_entry"
:
status
}
url
=
"/"
.
join
([
self
.
settings
.
base_url
,
self
.
_uid
,
"history"
])
return
self
.
_req
(
method
=
"put"
,
url
=
url
,
json
=
payload
)
return
self
.
_req
(
method
=
"put"
,
url
=
url
,
json
=
payload
,
**
kwargs
)
def
register_error_for_building
(
self
,
error_code
:
str
):
"""
...
...
@@ -91,9 +113,7 @@ class BuildingGeneric:
"""Upload the facade metadata to Hbase"""
body
=
{
"metadata"
:
payload
}
self
.
_req_with_retries
(
"post"
,
"/"
.
join
([
self
.
settings
.
base_url
,
self
.
_uid
,
"metadata"
,
name
]),
json
=
body
,
"post"
,
"/"
.
join
([
self
.
settings
.
base_url
,
self
.
_uid
,
"metadata"
,
name
]),
json
=
body
,
)
# ----------------- Roof level ---------------------
...
...
@@ -140,26 +160,29 @@ class BuildingGeneric:
image
=
self
.
_req_with_retries
(
"get"
,
"/"
.
join
([
self
.
settings
.
base_url
,
self
.
_uid
,
"facade"
,
facade_id
,
"image"
,
image_name
]),
"/"
.
join
(
[
self
.
settings
.
base_url
,
self
.
_uid
,
"facade"
,
facade_id
,
"image"
,
image_name
]
),
)
return
image
[
"image"
]
def
get_segmentation_vectors
(
self
,
facade_id
:
str
,
item
:
str
):
"""Get segmentation vectors for the specified item (eg: door) from Hbase"""
vectors
=
self
.
_req_with_retries
(
"get"
,
"/"
.
join
([
self
.
settings
.
base_url
,
self
.
_uid
,
"facade"
,
facade_id
,
item
,
"vectors"
])
"get"
,
"/"
.
join
([
self
.
settings
.
base_url
,
self
.
_uid
,
"facade"
,
facade_id
,
item
,
"vectors"
]),
)
return
vectors
def
upload_facade_image_by_name
(
self
,
facade_id
:
str
,
image_name
:
str
,
image
:
bytes
):
def
upload_facade_image_by_name
(
self
,
facade_id
:
str
,
image_name
:
str
,
image
:
bytes
):
"""Upload the facade image to Hbase"""
body
=
{
"image"
:
b64encode
(
image
).
decode
()}
self
.
_req_with_retries
(
"post"
,
"/"
.
join
([
self
.
settings
.
base_url
,
self
.
_uid
,
"facade"
,
facade_id
,
"image"
,
image_name
]),
"/"
.
join
(
[
self
.
settings
.
base_url
,
self
.
_uid
,
"facade"
,
facade_id
,
"image"
,
image_name
]
),
json
=
body
,
)
...
...
@@ -187,9 +210,7 @@ class BuildingGeneric:
for
v_index
,
visible_facade
in
enumerate
(
facade
[
"visible_facades"
]):
if
visible_facade
[
"id"
]
==
visible_facade_id
:
for
k
,
v
in
kwargs
.
items
():
self
.
_building
[
"facade"
][
f_index
][
"visible_facades"
][
v_index
][
k
]
=
v
self
.
_building
[
"facade"
][
f_index
][
"visible_facades"
][
v_index
][
k
]
=
v
def
filter_value
(
value
):
"""
...
...
@@ -221,11 +242,7 @@ class BuildingGeneric:
return
value
facade
=
[
{
k
:
filter_value
(
v
)
for
k
,
v
in
f
.
items
()
if
filter_value
(
v
)
or
filter_value
(
v
)
==
0
}
{
k
:
filter_value
(
v
)
for
k
,
v
in
f
.
items
()
if
filter_value
(
v
)
or
filter_value
(
v
)
==
0
}
for
f
in
self
.
_building
[
"facade"
]
]
...
...
@@ -261,8 +278,21 @@ class BuildingGeneric:
headers
=
{}
headers
=
{
**
headers
,
"Api-Key"
:
self
.
settings
.
api_key
}
res
=
requests
.
request
(
method
,
url
,
json
=
json
,
headers
=
headers
,
timeout
=
timeout
,
**
kwargs
)
res
.
raise_for_status
()
try
:
res
=
requests
.
request
(
method
,
url
,
json
=
json
,
headers
=
headers
,
timeout
=
timeout
,
**
kwargs
)
res
.
raise_for_status
()
except
HTTPError
as
e
:
if
(
e
.
response
.
status_code
==
500
and
"version conflict error"
in
e
.
response
.
text
.
lower
()
):
raise
VersionConflictError
else
:
raise
try
:
return
res
.
json
()
except
JSONDecodeError
:
...
...
@@ -272,6 +302,7 @@ class BuildingGeneric:
def
_force_update_with_version
(
self
,
payload
:
dict
,
url
:
str
)
->
None
:
"""
Update doc using current doc version to prevent version conflict errors
This will trigger a VersionConflictError on version conflict
Retry if VersionConflictError
"""
self
.
fetch
()
...
...
@@ -283,13 +314,6 @@ class BuildingGeneric:
Update ES doc using the version of the doc that was fetched
Use this to prevent version conflict when uploading data
"""
try
:
res
=
self
.
_req
(
"put"
,
url
,
json
=
{
**
payload
,
"version"
:
str
(
self
.
_building
[
"version"
])}
)
except
HTTPError
as
e
:
if
e
.
response
.
status_code
==
500
and
"version conflict error"
in
e
.
response
.
text
.
lower
():
raise
VersionConflictError
else
:
raise
return
res
res
=
self
.
_req
(
"put"
,
url
,
json
=
{
**
payload
,
"version"
:
str
(
self
.
_building
[
"version"
])})
building_dao/settings.py
View file @
3d684c94
...
...
@@ -5,7 +5,7 @@ from MaxIcsRegistry import MaxIcsRegistry
class
Settings
:
"""Settings for BKC communication"""
def
__init__
(
self
,
staging
:
bool
=
False
,
registry
=
None
)
->
None
:
def
__init__
(
self
,
staging
:
bool
=
False
,
registry
=
None
,
**
kwargs
)
->
None
:
if
not
registry
:
registry
=
MaxIcsRegistry
.
from_env
(
staging
=
staging
)
...
...
@@ -13,6 +13,13 @@ class Settings:
building_center_info
=
registry
.
get_info
(
"building-knowledge-information-center"
)
self
.
api_key
=
next
(
iter
(
building_center_info
[
"api_in"
].
values
()))[
"key"
]
self
.
base_url
=
"http://{}:{}/api/buildings"
.
format
(
building_center_info
[
"service_addr"
],
building_center_info
[
"service_port"
]
)
if
"base_url"
in
kwargs
.
keys
():
self
.
base_url
=
kwargs
[
"base_url"
]
else
:
self
.
base_url
=
"http://{}:{}/api/buildings"
.
format
(
building_center_info
[
"service_addr"
],
building_center_info
[
"service_port"
]
)
def
__str__
(
self
):
return
"Settings __dict__: %s"
%
str
(
self
.
__dict__
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment