簡體   English   中英

發布到 kafka 主題的浮士德示例

[英]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!")

或者:

這是你在做什么:

  1. example_sender() 向 hello(...) 發送消息(通過中間 kstream)
  2. hello(...) 接收消息並打印它 注意:沒有向正確的主題發送消息

您可以執行以下操作:

  1. example_sender() 向 hello(...) 發送消息(通過中間 kstream)

  2. hello(...) 接收消息並打印

  3. 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM