Instead of peeling nodes by in-degree, you can use DFS. Run DFS from each unvisited node. When a node finishes (all descendants explored), push it onto a stack. After all DFS calls complete, the stack holds the topological order.
Why does this work? A node finishes only after all reachable nodes have finished. So if edge exists, finishes before , meaning appears first in the reversed finish order.
To detect cycles, use colors: white (unvisited), gray (in progress), black (finished). If you visit a gray node, you found a back edge, which means a cycle. This runs in time and uses space.