Skip to content

Conversation

@Behzad-rabiei
Copy link
Member

@Behzad-rabiei Behzad-rabiei commented Jun 30, 2025

Summary by CodeRabbit

  • New Features

    • Added automated workflow execution for "Hivemind" modules on MediaWiki platforms when activated.
    • Introduced the ability to manage and terminate MediaWiki ETL workflows for improved platform integration.
  • Bug Fixes

    • Ensured workflows are only triggered if not already running, preventing duplicate executions.

@coderabbitai
Copy link

coderabbitai bot commented Jun 30, 2025

Walkthrough

This update adds special handling for the "Hivemind" module on the "MediaWiki" platform within the updateModule function. It introduces a helper to trigger a Temporal workflow through a new TemporalMediaWikiService class, which manages workflow execution and termination for MediaWiki ETL processes.

Changes

File(s) Change Summary
src/services/module.service.ts Added conditional logic for "Hivemind" with "MediaWiki" in updateModule; introduced private helper function to trigger workflow execution via new service.
src/services/temporal/mediaWiki.service.ts Introduced TemporalMediaWikiService class for managing MediaWiki ETL workflows; added methods for execution and termination; exported singleton instance.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant ModuleService
    participant PlatformModel
    participant TemporalMediaWikiService

    Client->>ModuleService: updateModule(moduleName="Hivemind", platform="MediaWiki", ...)
    ModuleService->>PlatformModel: findById(platformId)
    PlatformModel-->>ModuleService: platformDoc
    alt platform is activated and no workflowId
        ModuleService->>TemporalMediaWikiService: executeWorkflow(platformId)
        TemporalMediaWikiService-->>ModuleService: workflowHandle (with workflowId)
        ModuleService->>PlatformModel: save workflowId in platform metadata
    end
Loading

Possibly related PRs

Poem

In the warren of code, a new path appears,
Hivemind and MediaWiki now lend their ears.
Workflows are summoned, IDs take flight,
Temporal magic runs deep in the night.
Rabbits rejoice in orchestrated cheer—
ETL hops forward, the future is here!
🐇✨

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

npm error Exit handler never called!
npm error This is an error with npm itself. Please report this error at:
npm error https://github.com/npm/cli/issues
npm error A complete log of this run can be found in: /.npm/_logs/2025-06-30T16_08_41_919Z-debug-0.log

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@Behzad-rabiei Behzad-rabiei merged commit 76f3ae5 into main Jun 30, 2025
3 checks passed
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
src/services/temporal/mediaWiki.service.ts (1)

42-42: Consider adding type annotations for better type safety.

While the singleton pattern is appropriate, consider adding explicit type annotations for the exported instance to improve type safety and IDE support.

-export default new TemporalMediaWikiService();
+const temporalMediaWikiService: TemporalMediaWikiService = new TemporalMediaWikiService();
+export default temporalMediaWikiService;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aea1670 and d1f45f9.

📒 Files selected for processing (2)
  • src/services/module.service.ts (3 hunks)
  • src/services/temporal/mediaWiki.service.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
src/services/module.service.ts (2)
Learnt from: Behzad-rabiei
PR: TogetherCrew/api#350
File: src/services/module.service.ts:55-71
Timestamp: 2024-07-27T19:38:44.885Z
Learning: Error handling for the `updateModule` function in `src/services/module.service.ts` is managed by the parent function, as indicated by user Behzad-rabiei.
Learnt from: Behzad-rabiei
PR: TogetherCrew/api#350
File: src/services/module.service.ts:55-71
Timestamp: 2024-10-09T08:57:20.287Z
Learning: Error handling for the `updateModule` function in `src/services/module.service.ts` is managed by the parent function, as indicated by user Behzad-rabiei.
🔇 Additional comments (1)
src/services/module.service.ts (1)

97-99: LGTM! Clean integration with existing module update logic.

The conditional check follows the established pattern and integrates well with the existing codebase structure.

Comment on lines +32 to +39
public async terminateWorkflow(workflowId: string): Promise<void> {
const client: Client = await this.getClient();
const handle = client.workflow.getHandle(workflowId);
const description = await handle.describe();
if (description.status.name !== 'TERMINATED' && description.status.name !== 'COMPLETED') {
await handle.terminate('Terminated due to schedule deletion');
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling for workflow handle retrieval.

The terminateWorkflow method doesn't handle potential errors when getting the workflow handle or describing its status. If the workflow doesn't exist or is inaccessible, this could throw an unhandled exception.

 public async terminateWorkflow(workflowId: string): Promise<void> {
   const client: Client = await this.getClient();
-  const handle = client.workflow.getHandle(workflowId);
-  const description = await handle.describe();
-  if (description.status.name !== 'TERMINATED' && description.status.name !== 'COMPLETED') {
-    await handle.terminate('Terminated due to schedule deletion');
+  try {
+    const handle = client.workflow.getHandle(workflowId);
+    const description = await handle.describe();
+    if (description.status.name !== 'TERMINATED' && description.status.name !== 'COMPLETED') {
+      await handle.terminate('Terminated due to schedule deletion');
+    }
+  } catch (error) {
+    logger.error(`Failed to terminate workflow ${workflowId}: ${(error as Error).message}`);
+    throw new Error(`Failed to terminate workflow ${workflowId}: ${(error as Error).message}`);
   }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public async terminateWorkflow(workflowId: string): Promise<void> {
const client: Client = await this.getClient();
const handle = client.workflow.getHandle(workflowId);
const description = await handle.describe();
if (description.status.name !== 'TERMINATED' && description.status.name !== 'COMPLETED') {
await handle.terminate('Terminated due to schedule deletion');
}
}
public async terminateWorkflow(workflowId: string): Promise<void> {
const client: Client = await this.getClient();
try {
const handle = client.workflow.getHandle(workflowId);
const description = await handle.describe();
if (description.status.name !== 'TERMINATED' && description.status.name !== 'COMPLETED') {
await handle.terminate('Terminated due to schedule deletion');
}
} catch (error) {
logger.error(`Failed to terminate workflow ${workflowId}: ${(error as Error).message}`);
throw new Error(`Failed to terminate workflow ${workflowId}: ${(error as Error).message}`);
}
}
🤖 Prompt for AI Agents
In src/services/temporal/mediaWiki.service.ts around lines 32 to 39, the
terminateWorkflow method lacks error handling for failures when retrieving the
workflow handle or describing its status. Wrap the calls to getHandle and
describe in a try-catch block to catch any exceptions, and handle errors
gracefully by logging or rethrowing with a clear message to prevent unhandled
exceptions if the workflow is missing or inaccessible.

Comment on lines +13 to +30
public async executeWorkflow(platformId: Types.ObjectId) {
const client: Client = await this.getClient();
const payload = {
platform_id: platformId,
};
try {
const workflowHandle = await client.workflow.execute('MediaWikiETLWorkflow', {
taskQueue: queues.TEMPORAL_QUEUE_PYTHON_HEAVY,
args: [payload],
workflowId: `mediawiki/${platformId}/${uuidv4()}`,
});
logger.info(`Started MediaWiki workflow with ID: ${workflowHandle}`);
return workflowHandle;
} catch (error) {
logger.error(`Failed to trigger MediaWiki workflow: ${(error as Error).message}`);
throw new Error(`Failed to trigger MediaWiki workflow: ${(error as Error).message}`);
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify the return type and value of executeWorkflow method.

The method returns workflowHandle from client.workflow.execute(), but this value is later stored as workflowId in the platform metadata. Temporal's workflow.execute() typically returns a WorkflowHandle object, not a string ID.


🏁 Script executed:

#!/bin/bash
# Description: Check the return type of Temporal client.workflow.execute() method
# Expected: Confirm if it returns a WorkflowHandle object or a string ID

# Search for other usages of client.workflow.execute in the codebase
rg -A 10 "client\.workflow\.execute" --type ts

Length of output: 2072


🌐 Web query:

In Temporal TypeScript SDK, what is the return type of client.workflow.execute()?

💡 Result:

In the Temporal TypeScript SDK, the client.workflow.execute() method returns a Promise that resolves to the return value of the workflow's main function.

To elaborate, when you call execute() on a workflow, it starts the workflow execution and returns a promise. Once the workflow completes, the promise resolves with the workflow's result, which is the value returned by the workflow's main function.

For example, if your workflow function returns a string, then the return type of execute() will be Promise<string>. If it returns an object of some type, the promise will resolve to that object type.

Here is a simplified example:

const result: Promise<string> = client.workflow.execute(myWorkflow, {
  taskQueue: "my-task-queue",
  args: ["some input"],
});

If you want, I can provide more detailed code examples or official documentation references. Would you like that?


Fix executeWorkflow return type misuse: execute returns the workflow’s result, not a handle

In Temporal’s TypeScript SDK, client.workflow.execute() returns a Promise that resolves to whatever your workflow’s main function returns (e.g., a string or object), not a WorkflowHandle. Yet here you name the returned value workflowHandle, log it as an ID, and return it expecting to use it as a handle elsewhere (e.g. in terminateWorkflow).

You should either:

  • Switch to client.workflow.start() to obtain a true WorkflowHandle, then log and return its .workflowId, or
  • If you really want to wait for and return the workflow’s result, rename the variable to something like result/workflowResult, adjust your logging, and update your return type to match.

Locations to update:

  • src/services/temporal/mediaWiki.service.ts (lines 13–30)
  • Likewise in src/services/temporal/hivemind.service.ts for consistency

Example using start():

- const workflowHandle = await client.workflow.execute('MediaWikiETLWorkflow', { … });
- logger.info(`Started MediaWiki workflow with ID: ${workflowHandle}`);
- return workflowHandle;
+ const handle = await client.workflow.start('MediaWikiETLWorkflow', { … });
+ logger.info(`Started MediaWiki workflow with ID: ${handle.workflowId}`);
+ return handle;
🤖 Prompt for AI Agents
In src/services/temporal/mediaWiki.service.ts lines 13 to 30, the
executeWorkflow method incorrectly treats the result of
client.workflow.execute() as a WorkflowHandle, but it actually returns the
workflow's result. To fix this, replace client.workflow.execute() with
client.workflow.start() to get a true WorkflowHandle, then log and return its
workflowId. Update variable names accordingly to reflect that it is a handle,
not a result. Also ensure the return type matches the handle or workflowId.
Apply similar changes in src/services/temporal/hivemind.service.ts for
consistency.

Comment on lines +142 to +157
const handleHivemindMediaWikiCase = async (platform: any) => {
const platformDoc = await platformService.getPlatformById(platform.platform);

if (!platformDoc) return;

const isActivated = platform.metadata?.activated;
const existingWorkflowId = platformDoc.get('metadata.workflowId');

if (isActivated === true) {
if (!existingWorkflowId) {
const workflowId = await temporalMediaWiki.executeWorkflow(platform.platform);
platformDoc.set('metadata.workflowId', workflowId);
await platformDoc.save();
}
}
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Handle the deactivation scenario for consistency.

The handleHivemindMediaWikiCase function only handles the activation case but doesn't handle deactivation (when isActivated === false). This is inconsistent with the existing handleHivemindWebsiteCase function which handles both activation and deactivation scenarios.

 const handleHivemindMediaWikiCase = async (platform: any) => {
   const platformDoc = await platformService.getPlatformById(platform.platform);

   if (!platformDoc) return;

   const isActivated = platform.metadata?.activated;
   const existingWorkflowId = platformDoc.get('metadata.workflowId');

   if (isActivated === true) {
     if (!existingWorkflowId) {
       const workflowId = await temporalMediaWiki.executeWorkflow(platform.platform);
       platformDoc.set('metadata.workflowId', workflowId);
       await platformDoc.save();
     }
+  } else if (isActivated === false) {
+    if (existingWorkflowId) {
+      await temporalMediaWiki.terminateWorkflow(existingWorkflowId);
+      platformDoc.set('metadata.workflowId', null);
+      await platformDoc.save();
+    }
   }
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleHivemindMediaWikiCase = async (platform: any) => {
const platformDoc = await platformService.getPlatformById(platform.platform);
if (!platformDoc) return;
const isActivated = platform.metadata?.activated;
const existingWorkflowId = platformDoc.get('metadata.workflowId');
if (isActivated === true) {
if (!existingWorkflowId) {
const workflowId = await temporalMediaWiki.executeWorkflow(platform.platform);
platformDoc.set('metadata.workflowId', workflowId);
await platformDoc.save();
}
}
};
const handleHivemindMediaWikiCase = async (platform: any) => {
const platformDoc = await platformService.getPlatformById(platform.platform);
if (!platformDoc) return;
const isActivated = platform.metadata?.activated;
const existingWorkflowId = platformDoc.get('metadata.workflowId');
if (isActivated === true) {
if (!existingWorkflowId) {
const workflowId = await temporalMediaWiki.executeWorkflow(platform.platform);
platformDoc.set('metadata.workflowId', workflowId);
await platformDoc.save();
}
} else if (isActivated === false) {
if (existingWorkflowId) {
await temporalMediaWiki.terminateWorkflow(existingWorkflowId);
platformDoc.set('metadata.workflowId', null);
await platformDoc.save();
}
}
};
🤖 Prompt for AI Agents
In src/services/module.service.ts between lines 142 and 157, the function
handleHivemindMediaWikiCase currently only processes the activation scenario
when isActivated is true. To fix this, add logic to handle the deactivation case
when isActivated is false, similar to handleHivemindWebsiteCase. This should
include clearing or removing the workflowId from platformDoc metadata and saving
the document to maintain consistency in activation state handling.


if (isActivated === true) {
if (!existingWorkflowId) {
const workflowId = await temporalMediaWiki.executeWorkflow(platform.platform);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify workflow ID storage compatibility.

The executeWorkflow method likely returns a WorkflowHandle object, but this line stores it directly as workflowId. Ensure that the stored value is the correct string identifier that can be used later for workflow termination.


🏁 Script executed:

#!/bin/bash
# Description: Check how workflow IDs are typically stored and retrieved in the codebase
# Expected: Confirm the correct format for storing workflow identifiers

# Search for other workflow ID storage patterns
rg -A 5 -B 5 "workflowId.*=" --type ts

# Search for workflow ID retrieval patterns
rg -A 5 -B 5 "metadata\.workflowId" --type ts

Length of output: 1778


🏁 Script executed:

#!/bin/bash
# Locate executeWorkflow definition to inspect its return type
rg -n "executeWorkflow" --type ts

Length of output: 260


🏁 Script executed:

#!/bin/bash
# Print the implementation of executeWorkflow in the mediaWiki service
sed -n '1,200p' src/services/temporal/mediaWiki.service.ts

Length of output: 1655


Ensure you store the string ID from the WorkflowHandle

The executeWorkflow call returns a WorkflowHandle object, not a bare string. You need to pull out its workflowId property before persisting it. Otherwise you’ll save the entire handle object and pass it to terminateWorkflow, which expects a string.

• File: src/services/module.service.ts
• Around line 152

Suggested diff:

- const workflowId = await temporalMediaWiki.executeWorkflow(platform.platform);
- platformDoc.set('metadata.workflowId', workflowId);
+ const workflowHandle = await temporalMediaWiki.executeWorkflow(platform.platform);
+ const workflowId = workflowHandle.workflowId;
+ platformDoc.set('metadata.workflowId', workflowId);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const workflowId = await temporalMediaWiki.executeWorkflow(platform.platform);
const workflowHandle = await temporalMediaWiki.executeWorkflow(platform.platform);
const workflowId = workflowHandle.workflowId;
platformDoc.set('metadata.workflowId', workflowId);
🤖 Prompt for AI Agents
In src/services/module.service.ts at line 152, the variable workflowId is
assigned the entire WorkflowHandle object returned by executeWorkflow, but you
need to extract the string ID from this handle. Fix this by accessing the
workflowId property of the returned WorkflowHandle object and assign that string
to the workflowId variable before storing or passing it to terminateWorkflow.

@coderabbitai coderabbitai bot mentioned this pull request Jul 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants