![](/img/trans.png)
[英]How to connect kafka topic with web endpoint using Faust Python package?
[英]Faust example of publishing to a kafka topic
我很好奇您應該如何表達您希望將消息傳遞到浮士德的 Kafka 主題。 他們自述文件中的示例似乎沒有寫入主題:
import faust
class Greeting(faust.Record):
from_name: str
to_name: str
app = faust.App('hello-app', broker='kafka://localhost')
topic = app.topic('hello-topic', value_type=Greeting)
@app.agent(topic)
async def hello(greetings):
async for greeting in greetings:
print(f'Hello from {greeting.from_name} to {greeting.to_name}')
@app.timer(interval=1.0)
async def example_sender(app):
await hello.send(
value=Greeting(from_name='Faust', to_name='you'),
)
if __name__ == '__main__':
app.main()
我希望上面代碼中的hello.send
向主題發布消息,但似乎沒有。
有許多閱讀主題的示例,以及許多使用 cli 推送臨時消息的示例。 梳理完文檔后,我沒有看到任何明確的在代碼中發布到主題的示例。 我只是瘋了,上面的代碼應該可以工作嗎?
您可以使用sink
告訴 Faust 在哪里交付代理函數的結果。 如果需要,您還可以一次使用多個主題作為接收器。
@app.agent(topic_to_read_from, sink=[destination_topic])
async def fetch(records):
async for record in records:
result = do_something(record)
yield result
send()
函數是正確調用以寫入主題的函數。 您甚至可以指定一個特定的分區,就像等效的 Java API 調用一樣。
這是send()
方法的參考:
https://faust.readthedocs.io/en/latest/reference/faust.topics.html#faust.topics.Topic.send
如果您只想要 Faust 生產者(不與消費者/接收器結合),那么原始問題實際上具有正確的代碼位,這是一個功能齊全的腳本,可將消息發布到任何 Kafka 均可使用的“faust_test”Kafka 主題/浮士德消費者。
像這樣運行下面的代碼: python faust_producer.py worker
"""Simple Faust Producer"""
import faust
if __name__ == '__main__':
"""Simple Faust Producer"""
# Create the Faust App
app = faust.App('faust_test_app', broker='localhost:9092')
topic = app.topic('faust_test')
# Send messages
@app.timer(interval=1.0)
async def send_message(message):
await topic.send(value='my message')
# Start the Faust App
app.main()
所以我們剛遇到需要向接收sink
主題以外的主題發送消息。
我們找到的最簡單的方法是: foo = await my_topic.send_soon(value="wtfm8")
。
您還可以使用 asyncio 事件循環直接使用send
,如下所示。
loop = asyncio.get_event_loop()
foo = await ttopic.send(value="wtfm8??")
loop.run_until_complete(foo)
不知道這有多么重要,但我在嘗試學習 Faust 時遇到了這個問題。 從我讀到的,這是正在發生的事情:
topic = app.topic('hello-topic', value_type=Greeting)
這里的誤解是您創建的主題是您嘗試使用/讀取的主題。 您創建的主題當前不執行任何操作。
await hello.send(
value=Greeting(from_name='Faust', to_name='you'),
)
這實質上創建了一個中間 kstream,它將值發送到您的 hello(greetings) 函數。 def hello(...) 將在有新消息發送到流時被調用,並將處理正在發送的消息。
@app.agent(topic)
async def hello(greetings):
async for greeting in greetings:
print(f'Hello from {greeting.from_name} to {greeting.to_name}')
這是從 hello.send(...) 接收 kafka 流並簡單地將其打印到控制台(沒有輸出到創建的“主題”)。 您可以在此處向新主題發送消息。 因此,您可以執行以下操作而不是打印:
topic.send(value = "my message!")
或者:
這是你在做什么:
您可以執行以下操作:
example_sender() 向 hello(...) 發送消息(通過中間 kstream)
hello(...) 接收消息並打印
hello(...) 還向創建的主題發送一條新消息(假設您正在嘗試轉換原始數據)
app = faust.App('hello-app', broker='kafka://localhost') topic = app.topic('hello-topic', value_type=Greeting) output_topic = app.topic('test_output_faust', value_type=str) @app.agent(topic) async def hello(greetings): async for greeting in greetings: new_message = f'Hello from {greeting.from_name} to {greeting.to_name}' print(new_message) await output_topic.send(value=new_message)
我找到了如何使用 Faust 將數據發送到 kafka 主題的解決方案,但我並不真正了解它是如何工作的。
Faust 中有幾種方法: send(), cast(), ask_nowait(), ask()
。 在文檔中,它們被稱為 RPC 操作。
創建發送任務后,您需要在Client-Only Mode 模式下運行 Faust 應用程序。 ( start_client(), maybe_start_client()
)
以下代碼(produce() 函數)演示了它們的應用程序(注意注釋):
import asyncio
import faust
class Greeting(faust.Record):
from_name: str
to_name: str
app = faust.App('hello-app', broker='kafka://localhost')
topic = app.topic('hello-topic', value_type=Greeting)
result_topic = app.topic('result-topic', value_type=str)
@app.agent(topic)
async def hello(greetings):
async for greeting in greetings:
s = f'Hello from {greeting.from_name} to {greeting.to_name}'
print(s)
yield s
async def produce(to_name):
# send - universal method for sending data to a topic
await hello.send(value=Greeting(from_name='SEND', to_name=to_name), force=True)
await app.maybe_start_client()
print('SEND')
# cast - allows you to send data without waiting for a response from the agent
await hello.cast(value=Greeting(from_name='CAST', to_name=to_name))
await app.maybe_start_client()
print('CAST')
# ask_nowait - it seems to be similar to cast
p = await hello.ask_nowait(
value=Greeting(from_name='ASK_NOWAIT', to_name=to_name),
force=True,
reply_to=result_topic
)
# without this line, ask_nowait will not work; taken from the ask implementation
await app._reply_consumer.add(p.correlation_id, p)
await app.maybe_start_client()
print(f'ASK_NOWAIT: {p.correlation_id}')
# blocks the execution flow
# p = await hello.ask(value=Greeting(from_name='ASK', to_name=to_name), reply_to=result_topic)
# print(f'ASK: {p.correlation_id}')
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(produce('Faust'))
使用命令faust -A <example> worker
然后我們可以啟動應用程序的客戶端部分並檢查一切是否正常: python <example.py>
<example.py> 輸出:
SEND
CAST
ASK_NOWAIT: bbbe6795-5a99-40e5-a7ad-a9af544efd55
值得注意的是,您還會看到交付后發生的一些錯誤的回溯,這不會干擾程序(似乎如此)
浮士德工人輸出:
[2022-07-19 12:06:27,959] [1140] [WARNING] Hello from SEND to Faust
[2022-07-19 12:06:27,960] [1140] [WARNING] Hello from CAST to Faust
[2022-07-19 12:06:27,962] [1140] [WARNING] Hello from ASK_NOWAIT to Faust
我不明白為什么它會這樣工作,為什么這么難,為什么文檔中寫的很少 😓。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.