-
-
Save kylemclaren/3c09a4dda5991cf0bf9c to your computer and use it in GitHub Desktop.
| db.currentOp().inprog.forEach( | |
| function(op) { | |
| if(op.secs_running > 5) printjson(op); | |
| } | |
| ) |
| // kills long running ops in MongoDB (taking seconds as an arg to define "long") | |
| // attempts to be a bit safer than killing all by excluding replication related operations | |
| // and only targeting queries as opposed to commands etc. | |
| killLongRunningOps = function(maxSecsRunning) { | |
| currOp = db.currentOp(); | |
| for (oper in currOp.inprog) { | |
| op = currOp.inprog[oper-0]; | |
| if (op.secs_running > maxSecsRunning && op.op == "query" && !op.ns.startsWith("local")) { | |
| print("Killing opId: " + op.opid | |
| + " running for over secs: " | |
| + op.secs_running); | |
| db.killOp(op.opid); | |
| } | |
| } | |
| }; | |
| //example: killLongRunningOps(5) |
Hi i am a devops engineer, and using mongodb percona in replicaset wondering if this is a production ready script cz i guess we should ignore system queries like .local admin cmd and configs also what about index builds operations here is my script let me know if you guys can test it for edge cases
`#!/usr/bin/env python3
import argparse
import sys
import re
from pymongo import MongoClient
from pymongo.errors import PyMongoError
def parse_args():
parser = argparse.ArgumentParser(
description="Safely kill long-running MongoDB operations (production-ready)"
)
parser.add_argument(
"--uri",
required=True,
help="MongoDB connection string (mongodb+srv://...)"
)
parser.add_argument(
"--seconds",
type=int,
required=True,
help="Kill operations running longer than this many seconds"
)
parser.add_argument(
"--dry-run",
action="store_true",
help="Only print operations, do not kill"
)
parser.add_argument(
"--max-kills",
type=int,
default=3,
help="Maximum operations to kill per run (default: 3)"
)
return parser.parse_args()
def main():
args = parse_args()
print("[INFO] MongoDB long-op killer starting")
print(f"[INFO] Threshold : {args.seconds}s")
print(f"[INFO] Dry run : {args.dry_run}")
print(f"[INFO] Max kills : {args.max_kills}")
try:
client = MongoClient(args.uri, serverSelectionTimeoutMS=5000)
admin_db = client.admin
# --- ENSURE PRIMARY ---
hello = admin_db.command("hello")
if not hello.get("isWritablePrimary"):
print("[INFO] Node is not PRIMARY, exiting safely")
return 0
# --- FETCH LONG RUNNING OPS ---
current_ops = admin_db.command(
"currentOp",
{
"active": True,
"secs_running": {"$gte": args.seconds},
"op": {"$ne": "none"}
}
)
inprog = current_ops.get("inprog", [])
if not inprog:
print("[INFO] No long-running operations found")
return 0
print(f"[INFO] Found {len(inprog)} candidate operations")
killed = 0
for op in inprog:
if killed >= args.max_kills:
print("[INFO] Kill limit reached, stopping")
break
ns = op.get("ns", "")
desc = op.get("desc", "")
secs = op.get("secs_running", 0)
opid = op.get("opid")
client_addr = op.get("client", "unknown")
# --- SAFETY FILTERS ---
if not ns:
continue
if ns.startswith(("local.", "config.", "admin.")):
continue
if re.search("Balancer", desc):
continue
# ----------------------
print(
f"[OP] opid={opid} "
f"secs={secs} "
f"ns={ns} "
f"client={client_addr}"
)
if args.dry_run:
continue
try:
admin_db.command("killOp", op=opid)
killed += 1
print(f"[KILLED] opid={opid}")
except PyMongoError as e:
print(f"[ERROR] Failed to kill opid={opid}: {e}")
print(f"[INFO] Completed. Ops killed: {killed}")
return 0
except PyMongoError as e:
print(f"[FATAL] MongoDB error: {e}")
return 1
except Exception as e:
print(f"[FATAL] Unexpected error: {e}")
return 1
if name == "main":
sys.exit(main())
`
Thanks for this, i ended up using a modified version: