EOX GitLab Instance
Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
ESA
PRISM
vsq
Commits
287397e9
Commit
287397e9
authored
May 07, 2021
by
Fabian Schindler
Browse files
Restructuring queue
Adding testing via gitlab CI
parent
bbddc9fd
Pipeline
#13169
failed with stage
in 1 minute and 10 seconds
Changes
9
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
.gitlab-ci.yml
0 → 100644
View file @
287397e9
image
:
python:latest
before_script
:
-
pip install -r requirements_dev.txt
-
pip install .
test
:
services
:
-
redis:latest
script
:
-
pytest
publish
:
script
:
-
pip install twine
-
python setup.py sdist bdist_wheel
-
TWINE_PASSWORD=${CI_JOB_TOKEN} TWINE_USERNAME=gitlab-ci-token python -m twine upload --repository-url https://gitlab.eox.at/api/v4/projects/${CI_PROJECT_ID}/packages/pypi dist/*
only
:
-
tags
requirements_dev.txt
View file @
287397e9
...
...
@@ -9,4 +9,6 @@ Sphinx==1.8.5
twine==1.14.0
Click==7.0
pytest==4.6.5
pytest-runner==5.1
\ No newline at end of file
pytest-runner==5.1
redis==3.5.3
aioredis==1.3.1
setup.py
View file @
287397e9
...
...
@@ -19,22 +19,21 @@ test_requirements = ['pytest>=3', ]
setup
(
author
=
"Fabian Schindler"
,
author_email
=
'fabian.schindler@eox.at'
,
python_requires
=
'>=3.
5
'
,
python_requires
=
'>=3.
6
'
,
classifiers
=
[
'Development Status :: 2 - Pre-Alpha'
,
'Intended Audience :: Developers'
,
'License :: OSI Approved :: MIT License'
,
'Natural Language :: English'
,
'Programming Language :: Python :: 3'
,
'Programming Language :: Python :: 3.5'
,
'Programming Language :: Python :: 3.6'
,
'Programming Language :: Python :: 3.7'
,
'Programming Language :: Python :: 3.8'
,
],
description
=
"
Python Boilerplate contains all the boilerplate you need to create a Python package.
"
,
description
=
""
,
entry_points
=
{
'console_scripts'
:
[
'vsq
=vsq.cli:main
'
,
'vsq
-sync=vsq.queue:cli
'
,
],
},
install_requires
=
requirements
,
...
...
@@ -47,7 +46,11 @@ setup(
setup_requires
=
setup_requirements
,
test_suite
=
'tests'
,
tests_require
=
test_requirements
,
url
=
'https://github.com/constantinius/vsq'
,
extras_require
=
{
'sync'
:
[
'redis'
],
'async'
:
[
'aioredis'
],
},
url
=
'https://gitlab.eox.at/esa/prism/vsq'
,
version
=
'0.0.1'
,
zip_safe
=
False
,
)
tests/test_queue.py
View file @
287397e9
...
...
@@ -8,19 +8,22 @@ from vsq.queue import (
Queue
,
TaskFailedException
,
TaskTimeoutException
,
TaskStatus
)
@
pytest
.
fixture
def
queue
():
def
redis
():
redis
=
Redis
(
'localhost'
,
6379
,
)
yield
redis
redis
.
flushall
()
@
pytest
.
fixture
def
queue
(
redis
):
yield
Queue
(
'name'
,
redis
,
# fakeredis.FakeStrictRedis()
)
redis
.
flushall
()
def
test_basic
(
queue
):
...
...
@@ -87,9 +90,30 @@ def test_error(queue):
pass
with
pytest
.
raises
(
TaskFailedException
):
task
.
get
()
task
.
get
(
0.25
)
def
test_timeouts
(
queue
):
with
pytest
.
raises
(
TaskTimeoutException
):
queue
.
get_task
(
0.25
)
def
test_pubsub
(
redis
):
p
=
redis
.
pubsub
()
# redis.publish('test', 'message1')
p
.
subscribe
(
'test'
)
redis
.
publish
(
'test'
,
'message2'
)
redis
.
publish
(
'test'
,
'message3'
)
print
(
p
.
get_message
(
timeout
=
1.1
))
print
(
p
.
get_message
(
True
,
timeout
=
1.1
))
print
(
p
.
get_message
(
True
,
timeout
=
1.1
))
vsq/__init__.py
View file @
287397e9
"""Top-level package for View Server Task Queue."""
# ------------------------------------------------------------------------------
#
# Project: vsq <https://gitlab.eox.at/esa/prism/vsq>
# Authors: Fabian Schindler <fabian.schindler@eox.at>
#
# ------------------------------------------------------------------------------
# Copyright (C) 2021 EOX IT Services GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies of this Software or works derived from this Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# ------------------------------------------------------------------------------
__author__
=
"""Fabian Schindler"""
__email__
=
'fabian.schindler@eox.at'
...
...
vsq/aqueue.py
View file @
287397e9
# ------------------------------------------------------------------------------
#
# Project: vsq <https://gitlab.eox.at/esa/prism/vsq>
# Authors: Fabian Schindler <fabian.schindler@eox.at>
#
# ------------------------------------------------------------------------------
# Copyright (C) 2021 EOX IT Services GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies of this Software or works derived from this Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# ------------------------------------------------------------------------------
vsq/common.py
View file @
287397e9
# ------------------------------------------------------------------------------
#
# Project: vsq <https://gitlab.eox.at/esa/prism/vsq>
# Authors: Fabian Schindler <fabian.schindler@eox.at>
#
# ------------------------------------------------------------------------------
# Copyright (C) 2021 EOX IT Services GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies of this Software or works derived from this Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# ------------------------------------------------------------------------------
import
enum
from
datetime
import
datetime
,
timezone
from
typing
import
Dict
,
List
,
Union
...
...
@@ -22,8 +49,7 @@ class TaskFailedException(Exception):
class
TaskTimeoutException
(
Exception
):
def
__init__
(
self
,
error
):
self
.
error
=
error
pass
class
TaskStatus
(
enum
.
Enum
):
...
...
vsq/logging.py
0 → 100644
View file @
287397e9
# ------------------------------------------------------------------------------
#
# Project: vsq <https://gitlab.eox.at/esa/prism/vsq>
# Authors: Fabian Schindler <fabian.schindler@eox.at>
#
# ------------------------------------------------------------------------------
# Copyright (C) 2021 EOX IT Services GmbH
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies of this Software or works derived from this Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# ------------------------------------------------------------------------------
import
logging.config
def
setup_logging
(
debug
=
False
):
logging
.
config
.
dictConfig
({
'version'
:
1
,
'disable_existing_loggers'
:
False
,
'formatters'
:
{
'brief'
:
{
'format'
:
'%(levelname)s %(name)s: %(message)s'
}
},
'handlers'
:
{
'console'
:
{
'class'
:
'logging.StreamHandler'
,
'level'
:
'DEBUG'
if
debug
else
'INFO'
,
'formatter'
:
'brief'
,
}
},
'root'
:
{
'handlers'
:
[
'console'
],
'level'
:
'DEBUG'
if
debug
else
'INFO'
,
}
})
vsq/queue.py
View file @
287397e9
# ------------------------------------------------------------------------------
#
# Project: vsq <https://git
hub.com/geopython/pygeofilter
>
# Project: vsq <https://git
lab.eox.at/esa/prism/vsq
>
# Authors: Fabian Schindler <fabian.schindler@eox.at>
#
# ------------------------------------------------------------------------------
...
...
@@ -25,21 +25,79 @@
# THE SOFTWARE.
# ------------------------------------------------------------------------------
import
sys
import
enum
import
json
from
dataclasses
import
dataclass
,
field
,
asdict
from
datetime
import
datetime
from
uuid
import
uuid4
from
weakref
import
ref
from
typing
import
Optional
from
typing
import
Optional
,
Any
from
traceback
import
format_tb
import
logging
from
importlib
import
import_module
from
time
import
time
import
redis
from
redis
import
Redis
,
TimeoutError
import
click
from
.common
import
(
TaskStatus
,
MessageType
,
now
,
QueueClosedError
,
TaskFailedException
,
TaskTimeoutException
)
from
.logging
import
setup_logging
logger
=
logging
.
getLogger
(
__name__
)
class
ResponseChannel
:
def
send_response
(
self
,
response
:
bytes
):
raise
NotImplementedError
()
def
wait_for_response
(
self
,
timeout
:
float
=
None
):
raise
NotImplementedError
()
class
ListResponseChannel
(
ResponseChannel
):
def
__init__
(
self
,
redis
:
Redis
,
channel_name
:
str
,
expires
:
int
=
120
):
self
.
redis
=
redis
self
.
channel_name
=
channel_name
self
.
expires
=
expires
def
send_response
(
self
,
response
:
bytes
):
self
.
redis
.
lpush
(
self
.
channel_name
,
response
)
if
self
.
expires
is
not
None
:
self
.
redis
.
expire
(
self
.
channel_name
,
self
.
expires
)
def
wait_for_response
(
self
,
timeout
:
float
=
None
):
_
,
response
=
self
.
redis
.
brpop
(
self
.
channel_name
,
timeout
)
return
response
class
PubSubResponseChannel
(
ResponseChannel
):
def
__init__
(
self
,
redis
:
Redis
,
channel_name
:
str
):
self
.
redis
=
redis
self
.
channel_name
=
channel_name
self
.
pubsub
=
redis
.
pubsub
()
self
.
pubsub
.
subscribe
(
channel_name
)
def
send_response
(
self
,
response
:
bytes
):
self
.
redis
.
publish
(
self
.
channel_name
,
response
)
def
wait_for_response
(
self
,
timeout
:
float
=
None
):
while
timeout
is
None
or
timeout
>
0.0
:
current
=
time
()
message
=
self
.
pubsub
.
get_message
(
timeout
=
timeout
)
if
message
[
'type'
]
==
'message'
:
value
=
json
.
loads
(
message
[
'data'
])
return
value
if
timeout
is
not
None
:
timeout
-=
time
()
-
current
@
dataclass
...
...
@@ -47,7 +105,7 @@ class Task:
"""
"""
queue_ref
:
ref
[
'Queue'
]
response_channel
:
ResponseChannel
status
:
TaskStatus
=
TaskStatus
.
ACCEPTED
id
:
str
=
field
(
default_factory
=
lambda
:
uuid4
().
hex
)
message
:
Optional
[
MessageType
]
=
None
...
...
@@ -76,43 +134,53 @@ class Task:
'traceback'
:
format_tb
(
traceback
),
}
queue
=
self
.
queue_ref
()
if
not
queue
:
raise
QueueClosedError
()
queue
.
send_task_response
(
self
)
self
.
response_channel
.
send_response
(
self
.
encode
())
return
True
def
encode
(
self
):
def
default
(
o
):
print
(
o
)
if
isinstance
(
o
,
datetime
):
return
o
.
isoformat
()
# elif isinstance(o, traceback):
# return format_tb(o)
# elif issubclass(o, Exception):
# return str(o)
elif
isinstance
(
o
,
Exception
):
return
str
(
o
)
elif
isinstance
(
o
,
TaskStatus
):
return
o
.
value
dct
=
asdict
(
self
)
del
dct
[
'queue_ref'
]
dct
=
{
'status'
:
self
.
status
,
'id'
:
self
.
id
,
'message'
:
self
.
message
,
'result'
:
self
.
result
,
'error'
:
self
.
error
,
'created'
:
self
.
created
,
'started'
:
self
.
started
,
'finished'
:
self
.
finished
,
}
return
json
.
dumps
(
dct
,
default
=
default
)
@
classmethod
def
decode
(
cls
,
queue_ref
,
raw_value
):
def
decode
(
cls
,
response_channel
,
raw_value
)
->
'Task'
:
values
=
json
.
loads
(
raw_value
)
started
=
(
datetime
.
fromisoformat
(
values
[
'started'
])
if
values
[
'started'
]
else
None
)
finished
=
(
datetime
.
fromisoformat
(
values
[
'finished'
])
if
values
[
'finished'
]
else
None
)
return
cls
(
queue_ref
,
response_channel
,
status
=
TaskStatus
(
values
[
'status'
]),
id
=
values
[
'id'
],
message
=
values
[
'message'
],
result
=
values
[
'result'
],
error
=
values
[
'error'
],
created
=
datetime
.
fromisoformat
(
values
[
'created'
]),
started
=
datetime
.
fromisoformat
(
values
[
'started'
])
if
values
[
'started'
]
else
None
,
finished
=
datetime
.
fromisoformat
(
values
[
'finished'
])
if
values
[
'finished'
]
else
None
,
started
=
started
,
finished
=
finished
,
)
# Producer API
...
...
@@ -123,11 +191,9 @@ class Task:
Optionally a timeout can be specified to abort when a certain
time has passed. This raises a ``TaskTimeoutException``
"""
queue
=
self
.
queue_ref
()
if
not
queue
:
raise
QueueClosedError
()
received
=
queue
.
wait_for_task_response
(
self
,
timeout
)
raw
=
self
.
response_channel
.
wait_for_response
(
timeout
)
received
=
self
.
decode
(
self
.
response_channel
,
raw
)
if
received
.
status
==
TaskStatus
.
FAILED
:
raise
TaskFailedException
(
received
.
error
)
...
...
@@ -149,77 +215,125 @@ class ResponseScheme(enum.Enum):
class
Queue
:
def
__init__
(
self
,
queue_name
:
str
,
connection
:
redis
.
Redis
,
def
__init__
(
self
,
queue_name
:
str
,
redis
:
Redis
,
message_scheme
:
MessageScheme
=
MessageScheme
.
LPUSH_RPOP
,
response_scheme
:
ResponseScheme
=
ResponseScheme
.
LPUSH_RPOP
,
response_channel_template
:
str
=
'response_{id}'
,
response_channel_expires
:
Optional
[
int
]
=
120
):
self
.
queue_name
=
queue_name
self
.
connection
=
connection
self
.
redis
=
redis
self
.
message_scheme
=
message_scheme
self
.
response_scheme
=
response_scheme
self
.
response_channel_template
=
response_channel_template
self
.
response_channel_expires
=
response_channel_expires
def
_get_response_channel
(
self
,
task
):
channel_name
=
self
.
response_channel_template
.
format
(
id
=
task
.
id
,
)
if
self
.
response_scheme
==
ResponseScheme
.
LPUSH_RPOP
:
return
ListResponseChannel
(
self
.
redis
,
channel_name
)
elif
self
.
response_scheme
==
ResponseScheme
.
PUBSUB
:
return
PubSubResponseChannel
(
self
.
redis
,
channel_name
)
def
put
(
self
,
message
:
MessageType
,
msg_id
:
str
=
None
)
->
Task
:
if
msg_id
is
not
None
:
task
=
Task
(
ref
(
self
)
,
id
=
msg_id
,
message
=
message
)
task
=
Task
(
None
,
id
=
msg_id
,
message
=
message
)
else
:
task
=
Task
(
ref
(
self
),
message
=
message
)
task
=
Task
(
None
,
message
=
message
)
task
.
response_channel
=
self
.
_get_response_channel
(
task
)
encoded
=
task
.
encode
()
if
self
.
message_scheme
in
(
MessageScheme
.
LPUSH_RPOP
,
MessageScheme
.
LPUSH_LPOP
):
self
.
connection
.
lpush
(
self
.
queue_name
,
encoded
)
self
.
redis
.
lpush
(
self
.
queue_name
,
encoded
)
elif
self
.
message_scheme
in
(
MessageScheme
.
RPUSH_RPOP
,
MessageScheme
.
RPUSH_LPOP
):
self
.
connection
.
rpush
(
self
.
queue_name
,
encoded
)
self
.
redis
.
rpush
(
self
.
queue_name
,
encoded
)
elif
self
.
message_scheme
==
MessageScheme
.
SADD_SPOP
:
self
.
connection
.
sadd
(
self
.
queue_name
,
encoded
)
self
.
redis
.
sadd
(
self
.
queue_name
,
encoded
)
return
task
def
get_task
(
self
,
timeout
:
float
=
None
)
->
Task
:
try
:
if
self
.
message_scheme
in
(
MessageScheme
.
RPUSH_LPOP
,
MessageScheme
.
LPUSH_LPOP
):
_
,
raw_value
=
self
.
connection
.
blpop
(
self
.
queue_name
)
result
=
self
.
redis
.
blpop
(
self
.
queue_name
,
timeout
)
elif
self
.
message_scheme
in
(
MessageScheme
.
RPUSH_RPOP
,
MessageScheme
.
LPUSH_RPOP
):
_
,
raw_value
=
self
.
connection
.
brpop
(
self
.
queue_name
)
result
=
self
.
redis
.
brpop
(
self
.
queue_name
,
timeout
)
elif
self
.
message_scheme
==
MessageScheme
.
SADD_SPOP
:
_
,
raw_value
=
self
.
connection
.
spop
(
self
.
queue_name
)
result
=
self
.
redis
.
spop
(
self
.
queue_name
,
timeout
)
return
Task
.
decode
(
ref
(
self
),
raw_value
)
except
redis
.
TimeoutError
:
if
result
is
None
:
raise
TaskTimeoutException
()
_
,
raw_value
=
result
task
=
Task
.
decode
(
None
,
raw_value
)
task
.
response_channel
=
self
.
_get_response_channel
(
task
)
return
task
except
TimeoutError
:
raise
TaskTimeoutException
()
def
__iter__
(
self
):
while
True
:
yield
self
.
get_task
()
def
wait_for_task_response
(
self
,
task
,
timeout
:
float
=
None
)
->
Task
:
channel_name
=
self
.
response_channel_template
.
format
(
id
=
task
.
id
,
)
if
self
.
response_scheme
==
ResponseScheme
.
LPUSH_RPOP
:
_
,
raw_value
=
self
.
connection
.
brpop
(
channel_name
,
timeout
)
return
Task
.
decode
(
ref
(
self
),
raw_value
)
else
:
raise
NotImplementedError
(
f
'Response scheme
{
self
.
response_scheme
.
name
}
is not '
'implemented'
)
def
send_task_response
(
self
,
task
):
channel_name
=
self
.
response_channel_template
.
format
(
id
=
task
.
id
,
)
if
self
.
response_scheme
==
ResponseScheme
.
LPUSH_RPOP
:
self
.
connection
.
lpush
(
channel_name
,
task
.
encode
())
if
self
.
response_channel_expires
is
not
None
:
self
.
connection
.
expire
(
channel_name
,
self
.
response_channel_expires
)
@
click
.
group
()
@
click
.
option
(
'--host'
,
type
=
str
)
@
click
.
option
(
'--port'
,
show_default
=
True
,
default
=
6379
,
type
=
int
)
@
click
.
option
(
'--debug'
,
type
=
bool
)
@
click
.
pass_context
def
cli
(
ctx
,
host
,
port
,
debug
):
ctx
.
ensure_object
(
dict
)
ctx
.
obj
[
'redis'
]
=
Redis
(
host
=
host
,
port
=
port
)
ctx
.
obj
[
'debug'
]
=
debug
setup_logging
(
debug
)
return
0
@
cli
.
command
()
@
click
.
argument
(
'name'
,
type
=
str
)
@
click
.
argument
(
'handler'
,
type
=
str
)
@
click
.
pass_context
def
daemon
(
ctx
,
name
,
handler
):
"""Start a task daemon listening on the specified queue"""
handler_mod
,
_
,
handler_name
=
handler
.
rpartition
(
'.'
)
handler_func
=
getattr
(
import_module
(
handler_mod
),
handler_name
)
queue
=
Queue
(
name
,
ctx
.
obj
[
'redis'
])
logger
.
debug
(
f
"waiting for tasks on queue '
{
name
}
'..."
)
for
task
in
queue
:
with
task
:
task
.
result
=
handler_func
(
task
.
message
)
@
cli
.
command
()
@
click
.
argument
(
'name'
,
type
=
str
)
@
click
.
argument
(
'value'
,
type
=
str
)
@
click
.
option
(
'-j'
,
'--json'
,
'as_json'
,
is_flag
=
True
,
type
=
bool
)
@
click
.
option
(
'-w'
,
'--wait'
,
is_flag
=
True
,
type
=
bool
)
@
click
.
pass_context
def
message
(
ctx
,
name
,
value
,
as_json
=
False
,
wait
=
False
):
"""Send a message to the specified queue"""
message
=
value
if
as_json
:
message
=
json
.
loads
(
message
)
queue
=
Queue
(
name
,
ctx
.
obj
[
'redis'
])
task
=
queue
.
put
(
message
)
if
wait
:
try
:
result
=
task
.
get
()
print
(
result
)
return
0
except
TaskFailedException
as
e
:
logger
.
exception
(
e
)
return
1
else
:
raise
NotImplementedError
(
f
'Response scheme
{
self
.
response_scheme
.
name
}
is not '
'implemented'
)
if
__name__
==
"__main__"
:
sys
.
exit
(
cli
())
# pragma: no cover