Repository: PrefectHQ/prefect

Issue:
No flow run state events in OSS except for Scheduled state types
### First check

- [X] I added a descriptive title to this issue.
- [X] I used the GitHub search to find a similar issue and didn't find it.
- [X] I searched the Prefect documentation for this issue.
- [X] I checked that this issue is related to Prefect and not one of its dependencies.

### Bug summary

When I run a flow using 3.0 and the prefect server, I only see flow run state change events for scheduled states. (I see them for both Scheduled and AwaitingRetry which are both Scheduled state types). I've doubled checked running the same flow in Cloud and see state change events for all state types. 

This affects automations. I only get a state change automation for when my run enters a scheduled state.  I do not get notifications about pending, running, completed or failed state types.  Equally, my flow run SLA automations do not trigger. 



### Reproduction

```python3
1. Install the latest prefect release candidate by running pip install prefect==3.0.0rc2
2. Run prefect server start
3. Deploy a flow using prefect deploy, local storage and local process worker
4. Start the local process worker
5. Run a flow from the UI - check that the flow run progresses past scheduled to pending, running etc
6. Go to the events page and filter by prefect.flow-run.* events - observe only scheduled state events
7.  Create an automation to notify you whenever a flow run enters any state.  Observe that you only get a notification about scheduled states. 
8. Create an SLA notification.
```


### Error

_No response_

### Versions

```Text
Version:             3.0.0rc2
API version:         0.8.4
Python version:      3.12.3
Git commit:          4d70aefb
Built:               Thu, Jun 6, 2024 2:53 PM
OS/Arch:             darwin/x86_64
Profile:             orion
Server type:         ephemeral
Pydantic version:    2.7.3
Server:
  Database:          sqlite
  SQLite version:    3.45.3
```


### Additional context

Same flow and steps as above:

What I see in Cloud - all state changes are shown:

![image](https://github.com/PrefectHQ/prefect/assets/40272060/37c004d7-3f2b-439e-98b2-5312ba1ecf27)

What I see in the OSS UI:

![image](https://github.com/PrefectHQ/prefect/assets/40272060/297d166c-aeb4-487c-a40f-0d3a9eee33b5)



Discussion:
I'm not able to reproduce this with a non-deployed flow:

![image](https://github.com/PrefectHQ/prefect/assets/8194/c51e9a79-5ae5-45fc-9e1c-1fda3fdcc737)

![image](https://github.com/PrefectHQ/prefect/assets/8194/6a44d051-af16-400a-a9c6-24cf6f87d384)

The events are coming through and are written to the DB within a second.

Will try with a worker and deployed flow...
Not able to repro with a deployed flow either:

![image](https://github.com/PrefectHQ/prefect/assets/8194/07ccb9d1-8c3e-4124-9dd1-b8eae467f00e)

latencies on the outbound socket are subsecond as well
We discovered that the behavior Jenny was seeing was due to her having unset the `PREFECT_API_URL` in her profile.  There's not necessarily an events/automations bug here, but there's definitely something surprising going on that I want to investigate further.  

Also, when Jenny tried to run `prefect events stream`, she got an error about `NoneType has no method replace` which is what pointed us to her not having her API url set, but this should have been a more human-friendly warning

Resolving patch:
diff --git a/src/prefect/workers/base.py b/src/prefect/workers/base.py
--- a/src/prefect/workers/base.py
+++ b/src/prefect/workers/base.py
@@ -42,8 +42,10 @@
 from prefect.logging.loggers import PrefectLogAdapter, flow_run_logger, get_logger
 from prefect.plugins import load_prefect_collections
 from prefect.settings import (
+    PREFECT_API_URL,
     PREFECT_EXPERIMENTAL_WARN,
     PREFECT_EXPERIMENTAL_WARN_ENHANCED_CANCELLATION,
+    PREFECT_TEST_MODE,
     PREFECT_WORKER_HEARTBEAT_SECONDS,
     PREFECT_WORKER_PREFETCH_SECONDS,
     get_current_settings,
@@ -521,6 +523,10 @@ async def setup(self):
         self._limiter = (
             anyio.CapacityLimiter(self._limit) if self._limit is not None else None
         )
+
+        if not PREFECT_TEST_MODE and not PREFECT_API_URL.value():
+            raise ValueError("`PREFECT_API_URL` must be set to start a Worker.")
+
         self._client = get_client()
         await self._client.__aenter__()
         await self._runs_task_group.__aenter__()


Test patch:
diff --git a/tests/workers/test_base_worker.py b/tests/workers/test_base_worker.py
--- a/tests/workers/test_base_worker.py
+++ b/tests/workers/test_base_worker.py
@@ -25,8 +25,10 @@
 from prefect.server.schemas.responses import DeploymentResponse
 from prefect.server.schemas.states import StateType
 from prefect.settings import (
+    PREFECT_API_URL,
     PREFECT_EXPERIMENTAL_ENABLE_ENHANCED_CANCELLATION,
     PREFECT_EXPERIMENTAL_WARN_ENHANCED_CANCELLATION,
+    PREFECT_TEST_MODE,
     PREFECT_WORKER_PREFETCH_SECONDS,
     get_current_settings,
     temporary_settings,
@@ -92,6 +94,21 @@ def enable_enhanced_cancellation():
         yield
 
 
+@pytest.fixture
+def no_api_url():
+    with temporary_settings(updates={PREFECT_TEST_MODE: False, PREFECT_API_URL: None}):
+        yield
+
+
+async def test_worker_requires_api_url_when_not_in_test_mode(no_api_url):
+    with pytest.raises(ValueError, match="PREFECT_API_URL"):
+        async with WorkerTestImpl(
+            name="test",
+            work_pool_name="test-work-pool",
+        ):
+            pass
+
+
 async def test_worker_creates_work_pool_by_default_during_sync(
     prefect_client: PrefectClient,
 ):