Resigned Employee Account Disable Alert: Practical Integration Solution from MySQL Multi-Source Aggregation to DingTalk Message Push
What Problem Does This Strategy Solve (Scenario & Value)
In a retail/manufacturing enterprise, HR, the Sihua system, Kingdee, MOM, and the quotation system each maintain their own employee status records. "An employee has resigned, but the corresponding account in another system has not been disabled" is one of the most common issues IT teams get flagged on during audits. In the past, this relied on manually running SQL comparisons every day, resulting in a high miss rate and a broken accountability chain. We used the Qeasy Data Integration Platform to build a strategy: from MySQL, a multi-source join finds "accounts that have been disabled but not synced to DingTalk," then formats each one into a Markdown message and pushes it to designated DingTalk recipients. The value is turning "people finding data" into "data finding people," with unified, traceable alert semantics.
Data Flow and Field Mapping (Source → Middle Layer → Target)
The overall flow is MySQL → DingTalk. On the source side, UNION ALL aggregates records from five categories—Sihua, Kingdee, MOM, quotation, and resigned personnel—into a unified structure. The middle layer normalizes field names in Qeasy. The target side calls DingTalk's topapi/message/corpconversation/asyncsend_v2 to push Markdown messages.
| Target Field | Source Field / Rule | Mapping Type | Description |
|---|---|---|---|
| robotCode | DingTalk robot code | CONSTANT | Written as a constant in Qeasy, centrally placed in the platform parameter area for easy rotation |
| userIds | {{userid}} (JSON array in SQL) | DIRECT | Recipients specified per system type to avoid "one-size-fits-all broadcast" |
| msgKey | sampleMarkdown | CONSTANT | DingTalk Markdown message template |
| msgParam | _function CONCAT(...) | TRANSFORM | Concatenates a Markdown JSON string |
| msgParam.title | IT Management - Account Notice | CONSTANT | Message title |
| msgParam.text.system | {{system}} | DIRECT | Source system label |
| msgParam.text.time | now() | TRANSFORM | Written at push time |
| msgParam.text.job_number | {{job_number}} | DIRECT | Employee job number |
| msgParam.text.name | {{name}} | DIRECT | Name on DingTalk side |
| msgParam.text.department | {{dept_tree_name}} | DIRECT | Department tree name |
| msgParam.text.title | {{title}} | DIRECT | Job title |
| msgParam.text.system_account | {{user_name}} | DIRECT | Login name in each business system |
| msgParam.text.system_name | {{real_name}} | DIRECT | Display name in each business system |
Note: this strategy does not involve _findCollection encoding mapping. All mappings are DIRECT / CONSTANT / TRANSFORM, which is the biggest difference between "alert-type sync" and "master data sync."
How to Configure in Qeasy
- Source connector: Choose MySQL's "WebAPI select" mode and paste
main_sqlverbatim. Leave:limitand:offsetas pagination parameters bound tomain_paramsinput fields; Qeasy will inject them automatically at schedule time. - Target connector: Choose the DingTalk "robot/work notification" API. Fill in
robotCodeand the robot code as constants—do not scatter them inside the strategy. One of Qeasy's common patterns is "centralized encoding mapping management": place such constants at the platform-level parameter area, and let strategies only reference variables. - Field mapping: All fields except
msgParamare DIRECT. FormsgParam, use the "expression" type, select_function CONCAT, and concatenate multiple{{}}variables with fixed strings into JSON. - Rate limiting and pagination: Keep the
< Ncount check in each sub-query; it ensures a single push does not exceed DingTalk's rate limit. Qeasy adds:limit :offsetas a secondary pagination safety net. - Observability: In Qeasy's "Run Logs," mark
systemandjob_numberas key fields, so when an alert fails you can directly locate which system and which record is involved.
Implementation Steps
We recommend three phases: incremental starting point → full-volume trigger → scheduling frequency, running on dual tracks:
- Phase 1 (Incremental starting point, ~1 hour window): Use the
date(update_time)>=CURDATE() and hour(update_time)=hour(now())in the resigned personnel sub-query as the "incremental anchor." On first go-live, widen theupdate_timewindow to "last 24 hours" for one run to verify message body assembly, recipient list, and DingTalk rate limit. - Phase 2 (Full-volume trigger, baseline verification): Use Qeasy's "manual trigger" to run a full pass, checking each pushed Markdown for field completeness and proper escaping (quotes inside JSON, double newlines). The most common pitfall here is Markdown's
\nand\n(two spaces + newline) being eaten by the platform—be sure to verify on a real DingTalk client. - Phase 3 (Scheduling frequency): Source at
28 12,18 * * 1-6, target at30 12,18 * * 1-6, twice on weekdays at noon and evening. The source runs 2 minutes earlier than the target—this is a lightweight version of the "staged header/body" approach common in Qeasy: reserve execution time for the source, let the target only handle pushing, with clear responsibility separation, and on failure you can distinguish "cannot fetch" from "cannot push."
Pitfall Review
- Column counts in
UNION ALLbranches don't match—only reported at runtime. A safe practice is to add a comment at the end of the SQL noting the standard column count per branch, and use Qeasy's "Data Preview" to confirm all 5 branches return 10 columns. - DingTalk userids are hardcoded as JSON arrays inside SQL; recipient changes require editing SQL. A more engineering-friendly approach is to extract
useridinto a "per-system-type" configuration table, useJOINin SQL to fetch them, and let Qeasy only handle system-based routing. now()is directly embedded in the message body, causing "alert content and push time don't match" confusion. We recommend separating "event time" (sourceupdate_time) from "push time" (now())—do not mix them.- Chinese punctuation and two-space newline characters in Markdown get escaped by DingTalk's server. Always verify on a real device during testing—don't just inspect the assembled JSON in logs.
- DingTalk robot/app code leakage.
robotCodeis sensitive credential. In Qeasy, it should go into the credential center; the strategy only references the variable name, avoiding plaintext in logs.
Applicable and Non-Applicable Scenarios
Applicable: Account governance, offboarding compliance, "status inconsistency" alerts across multiple business systems, and any scenario where you need to turn database alerts into IM messages to designated recipients. Not applicable: Two-way synchronization, scenarios requiring historical version retention, or master data sync that needs encoding mapping (e.g., materials, customers, suppliers). For those, please use Qeasy's "Master Data Sync" strategy template.