# Utility method for making calls to the microservices
def call_service(stem: str, name: str) -> str:
    base = f"http://localhost:9999/{stem}"
    url = f"{base}?name={urllib.parse.quote(name)}"

    response = requests.get(url)
    return response.text
```

Whether to implement Activities as class methods or functions is a design
choice left up to the developer when cross-activity state isn't needed. Both are
equally valid implementations.

### How to run Synchronous Activities on a Worker

When running synchronous Activities, the Worker
needs to have an `activity_executor`. Temporal
recommends using a `ThreadPoolExecutor` as shown here:

```python
with ThreadPoolExecutor(max_workers=42) as executor:
    worker = Worker(
        # ...
        activity_executor=executor,
        # ...
    )
```

## How to Implement Asynchronous Activities

The following code is an implementation of the preceding Activity, but as an
asynchronous Activity Definition.

It makes
a call to a microservice, accessed through HTTP, to request this
greeting in Spanish. This Activity uses the `aiohttp` library to make an async
safe HTTP request. Using the `requests` library here would have resulting in
blocking code within the async event loop, which will block the entire async
event loop. For more in-depth information about this issue, refer to the
[Python asyncio documentation](https://docs.python.org/3/library/asyncio-dev.html#running-blocking-code).

The following code also implements the Activity Definition as a class, rather than a
function. The `aiohttp` library requires an established `Session` to perform the
HTTP request. It would be inefficient to establish a `Session` every time an
Activity is invoked, so instead this code accepts a `Session` object as an instance
parameter and makes it available to the methods. This approach will also be
beneficial when the execution is over and the `Session` needs to be closed.

In this example, the Activity supplies the name in the URL and retrieves
the greeting from the body of the response.

```python

from temporalio import activity

class TranslateActivities:
    def __init__(self, session: aiohttp.ClientSession):
        self.session = session

    @activity.defn
    async def greet_in_spanish(self, name: str) -> str:
        greeting = await self.call_service("get-spanish-greeting", name)
        return greeting

    # Utility method for making calls to the microservices
    async def call_service(self, stem: str, name: str) -> str:
        base = f"http://localhost:9999/{stem}"
        url = f"{base}?name={urllib.parse.quote(name)}"

        async with self.session.get(url) as response:
            translation = await response.text()

            if response.status >= 400:
                raise ApplicationError(
                    f"HTTP Error {response.status}: {translation}",
                    # We want to have Temporal automatically retry 5xx but not 4xx
                    non_retryable=response.status < 500,
                )

            return translation
```

### How to run synchronous code from an asynchronous activity

If your Activity is asynchronous and you don't want to change it to synchronous,
but you need to run blocking code inside it,
then you can use python utility functions to run synchronous code
in an asynchronous function:

- [`loop.run_in_executor()`](https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor), which is also mentioned in the ["running blocking code" section of the "developing with asyncio" guide](https://docs.python.org/3/library/asyncio-dev.html#running-blocking-code)
- [`asyncio.to_thread()`](https://docs.python.org/3/library/asyncio-task.html#running-in-threads)

## When Should You Use Async Activities

Asynchronous Activities have many advantages, such as potential speed up of execution.
However, as discussed above, making unsafe calls within the async event loop
can cause sporadic and difficult to diagnose bugs. For this reason, we recommend
using asynchronous Activities _only_ when you are certain that your Activities
are async safe and don't make blocking calls.

If you experience bugs that you think may be a result of an unsafe call being made in an asynchronous Activity, convert it to a synchronous Activity and see if the issue resolves.

---

## Schedules - Python SDK

This page shows how to do the following:

- [Schedule a Workflow](#schedule-a-workflow)
  - [Create a Scheduled Workflow](#create)
  - [Backfill a Scheduled Workflow](#backfill)
  - [Delete a Scheduled Workflow](#delete)
  - [Describe a Scheduled Workflow](#describe)
  - [List a Scheduled Workflow](#list)
  - [Pause a Scheduled Workflow](#pause)
  - [Trigger a Scheduled Workflow](#trigger)
  - [Update a Scheduled Workflow](#update)
- [Temporal Cron Jobs](#temporal-cron-jobs)
- [Start Delay](#start-delay)

## Schedule a Workflow {#schedule-a-workflow}

**How to Schedule a Workflow Execution**

Scheduling Workflows is a crucial aspect of any automation process, especially when dealing with time-sensitive tasks. By scheduling a Workflow, you can automate repetitive tasks, reduce the need for manual intervention, and ensure timely execution of your business processes

Use any of the following action to help Schedule a Workflow Execution and take control over your automation process.

### Create a Scheduled Workflow {#create}

**How to create a Scheduled Workflow**

The create action enables you to create a new Schedule. When you create a new Schedule, a unique Schedule ID is generated, which you can use to reference the Schedule in other Schedule commands.

To create a Scheduled Workflow Execution in Python, use the [create_schedule()](https://python.temporal.io/temporalio.client.Client.html#create_schedule)
asynchronous method on the Client.
Then pass the Schedule ID and the Schedule object to the method to create a Scheduled Workflow Execution.
Set the `action` parameter to `ScheduleActionStartWorkflow` to start a Workflow Execution.
Optionally, you can set the `spec` parameter to `ScheduleSpec` to specify the schedule or set the `intervals` parameter to `ScheduleIntervalSpec` to specify the interval.
Other options include: `cron_expressions`, `skip`, `start_at`, and `jitter`.

  
    View the source code
  {' '}
  in the context of the rest of the application code.

```python