[GH-ISSUE #52] Progress bar issue #38

Closed
opened 2026-02-27 20:05:06 +03:00 by kerem · 7 comments
Owner

Originally created by @tomballgithub on GitHub (Jan 24, 2026).
Original GitHub issue: https://github.com/misiektoja/instagram_monitor/issues/52

Corner case, but wanted to share it, because I share a fix that might fix all cases.

Running in console mode with web interface. Clicked "send test webhook" and saw this in the console. It's the same issue where you cannot print during progress bar updates. And later a timestamp was added on top of the progress bar, so I updated what I pasted here

* Followings number changed by user kara.elaine.long from 4393 to 4404 (+11)
* Downloading Followings:   2%|▌                        | 96/4404 [10.5 names/req, reqs=8, mins=1.0, remain=47.5]* Sending test webhook notification (triggered via web dashboard) ...
* Downloading Followings:   2%|▌                       | 108/4404 [10.7 names/req, reqs=9, mins=1.1, remain=53.0]* Webhook notification sent successfully

Timestamp:                              Sat 24 Jan 2026, 16:19:21
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────
* Downloading Followings:  48%|█████████▌          | 2099/4404 [11.3 names/req, reqs=184, mins=19.4, remain=19.0]

The tqdm progress bar has a tqdm.write() mechanism that can be used instead of print().
Maybe that should be used for a case like this (or all cases) where you need to print during an active progress bar

Example code from tqdm site:

from tqdm.auto import tqdm, trange
from time import sleep

bar = trange(10)
for i in bar:
    # Print using tqdm class method .write()
    sleep(0.1)
    if not (i % 3):
        tqdm.write("Done task %i" % i)
    # Can also use bar.write()

Output looks like (it's not shown on the site), and those "Done task" writes are occurring during the progress bar.
It does a print to screen and then pushes progress bar to the next line:

❯ python tqdm_test.py
Done task 0
Done task 3
Done task 6
Done task 9
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:01<00:00,  9.67it/s]

Originally created by @tomballgithub on GitHub (Jan 24, 2026). Original GitHub issue: https://github.com/misiektoja/instagram_monitor/issues/52 Corner case, but wanted to share it, because I share a fix that might fix all cases. Running in console mode with web interface. Clicked "send test webhook" and saw this in the console. It's the same issue where you cannot print during progress bar updates. And later a timestamp was added on top of the progress bar, so I updated what I pasted here ``` * Followings number changed by user kara.elaine.long from 4393 to 4404 (+11) * Downloading Followings: 2%|▌ | 96/4404 [10.5 names/req, reqs=8, mins=1.0, remain=47.5]* Sending test webhook notification (triggered via web dashboard) ... * Downloading Followings: 2%|▌ | 108/4404 [10.7 names/req, reqs=9, mins=1.1, remain=53.0]* Webhook notification sent successfully Timestamp: Sat 24 Jan 2026, 16:19:21 ───────────────────────────────────────────────────────────────────────────────────────────────────────────────── * Downloading Followings: 48%|█████████▌ | 2099/4404 [11.3 names/req, reqs=184, mins=19.4, remain=19.0] ``` The tqdm progress bar has a tqdm.write() mechanism that can be used instead of print(). Maybe that should be used for a case like this (or all cases) where you need to print during an active progress bar Example code from tqdm site: ``` from tqdm.auto import tqdm, trange from time import sleep bar = trange(10) for i in bar: # Print using tqdm class method .write() sleep(0.1) if not (i % 3): tqdm.write("Done task %i" % i) # Can also use bar.write() ``` Output looks like (it's not shown on the site), and those "Done task" writes are occurring during the progress bar. It does a print to screen and then pushes progress bar to the next line: ``` ❯ python tqdm_test.py Done task 0 Done task 3 Done task 6 Done task 9 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:01<00:00, 9.67it/s] ```
kerem 2026-02-27 20:05:06 +03:00
  • closed this issue
  • added the
    bug
    label
Author
Owner

@tomballgithub commented on GitHub (Jan 24, 2026):

I wasn't using the latest code, I need to test 3.0

<!-- gh-comment-id:3795677849 --> @tomballgithub commented on GitHub (Jan 24, 2026): I wasn't using the latest code, I need to test 3.0
Author
Owner

@tomballgithub commented on GitHub (Jan 25, 2026):

I verified this still happened with 3.0 (scroll to the right in the sample below).
A few moments after the webhook check, the timestamp also gets written.

I think all that would be fine if the tdm.write() method is used per above, maybe in logger.write()?

* Downloading Followers:  12%|███▎                         | 22/190 [5.5 names/req, reqs=2, mins=0.2, remain=2.4]* Sending test webhook notification (triggered via web dashboard) ...
* Downloading Followers:  16%|████▋                        | 31/190 [7.3 names/req, reqs=3, mins=0.4, remain=1.7]* Sending test webhook notification (triggered via web dashboard) ...
* Webhook notification sent successfully

Timestamp:                              Sat 24 Jan 2026, 23:10:06
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────
* Downloading Followers:  20%|█████▊                       | 38/190 [7.8 names/req, reqs=4, mins=0.6, remain=2.3]* We
<!-- gh-comment-id:3796003255 --> @tomballgithub commented on GitHub (Jan 25, 2026): I verified this still happened with 3.0 (scroll to the right in the sample below). A few moments after the webhook check, the timestamp also gets written. I think all that would be fine if the tdm.write() method is used per above, maybe in logger.write()? ``` * Downloading Followers: 12%|███▎ | 22/190 [5.5 names/req, reqs=2, mins=0.2, remain=2.4]* Sending test webhook notification (triggered via web dashboard) ... * Downloading Followers: 16%|████▋ | 31/190 [7.3 names/req, reqs=3, mins=0.4, remain=1.7]* Sending test webhook notification (triggered via web dashboard) ... * Webhook notification sent successfully Timestamp: Sat 24 Jan 2026, 23:10:06 ───────────────────────────────────────────────────────────────────────────────────────────────────────────────── * Downloading Followers: 20%|█████▊ | 38/190 [7.8 names/req, reqs=4, mins=0.6, remain=2.3]* We ```
Author
Owner

@tomballgithub commented on GitHub (Jan 25, 2026):

I changed these prints to tqdm.write's and it didn't change the behavior:

    def api_test_webhook():  # type: ignore
        global WEBHOOK_URL, WEBHOOK_ENABLED
        if not WEBHOOK_URL:
            return jsonify({'success': False, 'error': 'WEBHOOK_URL is not set'}), 400  # type: ignore

        # print("* Sending test webhook notification1 (triggered via web dashboard) ...")
        tqdm.write("* Sending test webhook notification1 (triggered via web dashboard) ...")
        # Temporarily enable if we are testing
        old_webhook_enabled = WEBHOOK_ENABLED
        WEBHOOK_ENABLED = True
        res = send_webhook("instagram_monitor: test webhook", "This is **test webhook** - your settings seems to be **correct** !", color=0x7289DA)
        WEBHOOK_ENABLED = old_webhook_enabled

        if res == 0:
            # print_cur_ts("\nTimestamp:\t\t\t\t")
            tqdm.write(get_cur_ts(str("\nTimestamp:\t\t\t\t")))
            tqdm.write("─" * HORIZONTAL_LINE)
            return jsonify({'success': True})  # type: ignore
        print("* Error: Test webhook notification failed")
        # print_cur_ts("\nTimestamp:\t\t\t\t")
        tqdm.write(get_cur_ts(str("\nTimestamp:\t\t\t\t")))
        tqdm.write("─" * HORIZONTAL_LINE)
        return jsonify({'success': False, 'error': 'Failed to send test webhook. Check console logs.'}), 500  # type: ignore

Output:

* Downloading Followers:   6%|█▋                           | 11/190 [0.0 names/req, reqs=1, mins=0.1, remain=0.0]* Sending test webhook notification1 (triggered via web dashboard) ...
* Downloading Followers:  12%|███▎                         | 22/190 [5.5 names/req, reqs=2, mins=0.2, remain=1.5]* Webhook notification sent successfully

Timestamp:                              Sat 24 Jan 2026, 23:31:59
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────

<!-- gh-comment-id:3796019191 --> @tomballgithub commented on GitHub (Jan 25, 2026): I changed these prints to tqdm.write's and it didn't change the behavior: ``` def api_test_webhook(): # type: ignore global WEBHOOK_URL, WEBHOOK_ENABLED if not WEBHOOK_URL: return jsonify({'success': False, 'error': 'WEBHOOK_URL is not set'}), 400 # type: ignore # print("* Sending test webhook notification1 (triggered via web dashboard) ...") tqdm.write("* Sending test webhook notification1 (triggered via web dashboard) ...") # Temporarily enable if we are testing old_webhook_enabled = WEBHOOK_ENABLED WEBHOOK_ENABLED = True res = send_webhook("instagram_monitor: test webhook", "This is **test webhook** - your settings seems to be **correct** !", color=0x7289DA) WEBHOOK_ENABLED = old_webhook_enabled if res == 0: # print_cur_ts("\nTimestamp:\t\t\t\t") tqdm.write(get_cur_ts(str("\nTimestamp:\t\t\t\t"))) tqdm.write("─" * HORIZONTAL_LINE) return jsonify({'success': True}) # type: ignore print("* Error: Test webhook notification failed") # print_cur_ts("\nTimestamp:\t\t\t\t") tqdm.write(get_cur_ts(str("\nTimestamp:\t\t\t\t"))) tqdm.write("─" * HORIZONTAL_LINE) return jsonify({'success': False, 'error': 'Failed to send test webhook. Check console logs.'}), 500 # type: ignore ``` Output: ``` * Downloading Followers: 6%|█▋ | 11/190 [0.0 names/req, reqs=1, mins=0.1, remain=0.0]* Sending test webhook notification1 (triggered via web dashboard) ... * Downloading Followers: 12%|███▎ | 22/190 [5.5 names/req, reqs=2, mins=0.2, remain=1.5]* Webhook notification sent successfully Timestamp: Sat 24 Jan 2026, 23:31:59 ───────────────────────────────────────────────────────────────────────────────────────────────────────────────── ```
Author
Owner

@misiektoja commented on GitHub (Jan 25, 2026):

The tqdm.write() didn't work as it is a thread context mismatch. The progress bar lives in the monitoring thread, while the webhook message originates from the Flask web dashboard thread. When tqdm.write() is called from the dashboard thread, it doesn't have the context of the active progress bar in the other thread, so it just appends to the current line instead of clearing it.

Honestly I do not see any good solution for that. We could implement some kind of global registry to track active progress bars across threads. However, this adds significant architectural complexity and requires passing user/thread context to every part of the app that might print (webhooks, emails, status logs).

We could also queue messages and wait for the progress bar to finish. But since it might take long time (~40 minutes in your case), the feedback would arrive too late to be useful.

We could also suppress the message completely, but then it is gone forever.

<!-- gh-comment-id:3796750600 --> @misiektoja commented on GitHub (Jan 25, 2026): The tqdm.write() didn't work as it is a thread context mismatch. The progress bar lives in the monitoring thread, while the webhook message originates from the Flask web dashboard thread. When tqdm.write() is called from the dashboard thread, it doesn't have the context of the active progress bar in the other thread, so it just appends to the current line instead of clearing it. Honestly I do not see any good solution for that. We could implement some kind of global registry to track active progress bars across threads. However, this adds significant architectural complexity and requires passing user/thread context to every part of the app that might print (webhooks, emails, status logs). We could also queue messages and wait for the progress bar to finish. But since it might take long time (~40 minutes in your case), the feedback would arrive too late to be useful. We could also suppress the message completely, but then it is gone forever.
Author
Owner

@tomballgithub commented on GitHub (Jan 25, 2026):

Don't all prints go through your logger routine? Is there a central way to do this there? Such as if there is an active progress bar, to turn the print into a tqdm.write vis the correct thread?

That said, it's definitely not worth rearchitecting anything. This progress bar went from simple to complex once multi account monitoring was added.

<!-- gh-comment-id:3796823934 --> @tomballgithub commented on GitHub (Jan 25, 2026): Don't all prints go through your logger routine? Is there a central way to do this there? Such as if there is an active progress bar, to turn the print into a tqdm.write vis the correct thread? That said, it's definitely not worth rearchitecting anything. This progress bar went from simple to complex once multi account monitoring was added.
Author
Owner

@misiektoja commented on GitHub (Jan 29, 2026):

Yes, the Logger class is indeed the central bottleneck for all output.

But the tricky part (even at the Logger level) is thread isolation. Since progress bars are stored in _thread_local state to support multi-target monitoring, the Logger (when called from the web dashboard thread) can't see the active progress bar owned by a monitoring thread.

To bridge that gap, we'd need to implement that global registry I mentioned earlier which is quite tricky.

Given how progress bars became significantly more complex with the move to multi-account support, I think your suggestion to leave it as is for now is the most pragmatic approach. It keeps the core logging logic simple and avoids introducing new global state management just for test notifications.

<!-- gh-comment-id:3814881542 --> @misiektoja commented on GitHub (Jan 29, 2026): Yes, the Logger class is indeed the central bottleneck for all output. But the tricky part (even at the Logger level) is thread isolation. Since progress bars are stored in _thread_local state to support multi-target monitoring, the Logger (when called from the web dashboard thread) can't see the active progress bar owned by a monitoring thread. To bridge that gap, we'd need to implement that global registry I mentioned earlier which is quite tricky. Given how progress bars became significantly more complex with the move to multi-account support, I think your suggestion to leave it as is for now is the most pragmatic approach. It keeps the core logging logic simple and avoids introducing new global state management just for test notifications.
Author
Owner

@tomballgithub commented on GitHub (Jan 29, 2026):

Corner case, not worth fixing...

<!-- gh-comment-id:3815680303 --> @tomballgithub commented on GitHub (Jan 29, 2026): Corner case, not worth fixing...
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/instagram_monitor#38
No description provided.